Transducers are composable algorithmic transformations. They are independent from the context of their input and output sources and specify only the essence of the transformation in terms of an individual element. Because transducers are decoupled from input or output sources, they can be used in many different processes - collections, streams, channels, observables, etc. Transducers compose directly, without awareness of input or creation of intermediate aggregates.

OK, short in description... let's see why we need it

  1. Normal Javascript `map`,`filter` create inter variable and loop though array everytime we call `map` or `filter` function, `transducer` can loop thought the array only ONCE and apply all the transofrmations necessary.
const data = [,,];
const inc = x => x + ;
const double = x => * x;
const lessThanThree = x => x < ;
////////////////////
/**
* Problem: We loop over array 3 times! We want to loop over only once
* in order to improve the profermance.
*/
const res1 = data
.filter(lessThanThree)
.map(double)
.map(inc) console.log(res1) // [3,5]

  2. We don't want to introduce any mutation or impure function such as `forEach` does, transducer are mutation free.

/**
* Problem: it is not pure function and we do mutation. But it is faster
* than we do .filter.map.map style, because it only loop the array once.
*/
let res2 = [];
data.forEach((x) => {
let item;
if (lessThanThree(x)) {
item = inc(double(x))
res2.push(item);
}
})
console.log(res2) // [3,5]

  3. We want to style functional style to keep the code more readable, in the meanwhile improve the proferemance:

/**
* Good: We avoid the mutation and can be write as pure function and it only loop once!
* Problem: But we lose our function composion style! We still want .filter.map.map styling.
* Meanwhile it should be profermance wise.
*/
const res3 = data.reduce((acc, curr) => {
if (lessThanThree(curr)) {
acc.push(inc(double(curr)));
}
return acc;
}, []);
console.log(res3); // [3,5]

OK, until now, we have some idea, what kind of code we want. Basiclly it should be composable and efficient.

The question is how to make composable code?

As we might know about, in OOP; if we want to chain multi function calls, from each function, we need to return `this`:

Class Bot {
...
sayName() {
console.log(this,name)
return this;
} sayHello() {
console.log("Hello")
return this;
} } const b = new Bot('Petter') b.sayName().sayHello()

For Array, the reason we can chain calls together is because each call return Array type. The same as String, number...

The key is we need to keep the input and output as the same type!

Therefore for function, we need to keep input function and output function have the same function signature!

//data.reduce(reducer, seed), reducer is something we can compose!
//Because reducer :: (acc, curr) => acc
//For every reducer functions' signature are the same.
//If the function sinature are the same, then we can compose function together!
const _mapReducer = (xf, array) =>
array.reduce((acc, curr) => {
acc.push(xf(curr))
return acc;
}, []);
const _filterReducer = (xf, array) =>
array.reduce((acc, curr) => {
if (xf(curr)) acc.push(curr);
return acc;
}, []);
// To make fns easy to compose, we extract 'array' data & init value
const mapReducer = (xf) => ((acc, curr) => {
acc.push(xf(curr))
return acc;
});
const filterReducer = pred => ((acc, curr) => {
if (pred(curr)) acc.push(curr);
return acc;
});
// now mapReducer and filterReducer both have the same function signature.
console.log(data.reduce(mapReducer(double), [])); // [2,4,6]
console.log(data.reduce(mapReducer(inc), [])); // [2,3,4]
console.log(data.reduce(filterReducer(lessThanThree), [])); // [1,2]
In order to compose reudcers together we need to make mapReducer and filterReducer as high order functions to take reducer as arguement, take a reducer as input and return a reducer signature as output is the key to do composion!
// In order to compose reudcers together we need to make mapReducer and filterReducer as high order functions to take reducer as arguement
// Take a reducer as input and return a reducer signature as output is the key to do composion!
const map = xf => reducer => ((acc, curr) => {
acc = reducer(acc, xf(curr))
return acc;
});
const filter = pred => reducer => ((acc, curr)=> {
if (pred(curr)) acc = reducer(acc, curr)
return acc;
})
// For mapReducer and filterReducer, we both do acc.push()
// therefore we can extrat this as base reducer
const pushReducer = (acc, value) => {
acc.push(value);
return acc;
};
Now we are able to use functional style and loop the array only once!
const doulbeLessThanThree = compose(
map(inc),
map(double),
filter(lessThanThree)
)
const res5 = data.reduce(doulbeLessThanThree(pushReducer), []);
console.log(res5); // [3,5]

Define our transducer!

/**
* transducer :: ((a -> b -> a), (a -> b -> a), [a], [a]) -> [a]
* @param {*} xf: base reducer
* @param {*} reducer: the composion redcuer signature
* @param {*} seed : init value
* @param {*} collection : data
*/
const transducer = (xf, reducer, seed, collection) => {
return collection.reduce(reducer(xf), seed);
}
const res6 = transducer(pushReducer, doulbeLessThanThree, [], data);
console.log(res6); // [3,5]

[Transducer] Step by Step to build a simple transducer的更多相关文章

  1. Build step 'Execute shell' marked build as failure解决

    今天jenkins构建时运行脚本报错如下: Build step 'Execute shell' marked build as failure 脚本没问题后来看了下原因是磁盘空间不足导致报错,清除下 ...

  2. Jenkins Build step 'Execute shell' marked build as failure

    问题出现: Jenkins一直都构建成功,今天突然报错:Jenkins Build step 'Execute shell' marked build as failure 问题原因: By defa ...

  3. [转]Bootstrap 3.0.0 with ASP.NET Web Forms – Step by Step – Without NuGet Package

    本文转自:http://www.mytecbits.com/microsoft/dot-net/bootstrap-3-0-0-with-asp-net-web-forms In my earlier ...

  4. Tomcat Clustering - A Step By Step Guide --转载

    Tomcat Clustering - A Step By Step Guide Apache Tomcat is a great performer on its own, but if you'r ...

  5. Code Understanding Step by Step - We Need a Task

      Code understanding is a task we are always doing, though we are not even aware that we're doing it ...

  6. 课程四(Convolutional Neural Networks),第一周(Foundations of Convolutional Neural Networks) —— 2.Programming assignments:Convolutional Model: step by step

    Convolutional Neural Networks: Step by Step Welcome to Course 4's first assignment! In this assignme ...

  7. Convolutional Neural Networks: Step by Step

    Andrew Ng deeplearning courese-4:Convolutional Neural Network Convolutional Neural Networks: Step by ...

  8. Sequence Models Week 1 Building a recurrent neural network - step by step

    Building your Recurrent Neural Network - Step by Step Welcome to Course 5's first assignment! In thi ...

  9. Step by step Process of creating APD

    Step by step Process of creating APD: Business Scenario: Here we are going to create an APD on top o ...

随机推荐

  1. linux 重写rm命令

    重写rm命令 replease rm to trash   必须使用root编辑/etc/bashrc vim /etc/bashrc 在最后面增加如下脚本 saferm () { if [ ! -d ...

  2. FileBuffer-ImageBuffer 模拟PE

    这节课的重点是:模拟PE加载过程,按照运行的要求给FileBuffer拉伸放到内存当中,从 FileBuffer 到 ImageBuffer 再到 运行Buffer. PE  加载  过程: 根据si ...

  3. Angular Material Starter App

      介绍 Material Design反映了Google基于Android 5.0 Lollipop操作系统的原生应用UI开发理念,而AngularJS还发起了一个Angular Material ...

  4. luogu P1011 车站

    题目描述 火车从始发站(称为第1站)开出,在始发站上车的人数为a,然后到达第2站,在第2站有人上.下车,但上.下车的人数相同,因此在第2站开出时(即在到达第3站之前)车上的人数保持为a人.从第3站起( ...

  5. [CF126D]Fibonacci Sums/[BJOI2012]最多的方案

    [CF126D]Fibonacci Sums/[BJOI2012]最多的方案 题目大意: 将\(n(n\le10^9)\)表示成若干个不同斐波那契数之和的形式,求方案数. 思路: 如果不考虑\(0\) ...

  6. asp.net 去除数据中带有的html标签

    1,在控制器中实现去除html标签的静态方法 //去除html标签 public static string ReplaceHtmlMark(object Contents) { string Htm ...

  7. AS3使用Json 传复杂数据 -------- 用数组而不是向量

    package { public class Person { private var name:String; public function get Name():String { return ...

  8. 解决数据库 Table 'content_tags' is marked as crashed and should be repaired 表损坏问题

    今天突然网站TAG页面打不开了,打开debug,发现提示 Table 'content_tags' is marked as crashed and should be repaired 这样的错误 ...

  9. gdb 调试的信息输出到文件

    # (gdb) set logging file <文件名> # (gdb) set logging on # (gdb) thread apply all bt # (gdb) set ...

  10. picker.js源码

    /** * LArea移动端城市选择控件 * * version:1.7.2 * * author:黄磊 * * git:https://github.com/xfhxbb/LArea * * Cop ...