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. 洛谷P2731 骑马修栅栏 [欧拉回路]

    题目传送门 骑马修栅栏 题目背景 Farmer John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. 题目描述 John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经 ...

  2. JAVAEE学习——hibernate04:查询种类、HQL、Criteria、查询优化和练习为客户列表增加查询条件

    一.查询种类 1.oid查询-get 2.对象属性导航查询 3.HQL 4.Criteria 5.原生SQL 二.查询-HQL语法 //学习HQL语法 public class Demo { //基本 ...

  3. shell 文件合并,去重,分割

    第一:两个文件的交集,并集前提条件:每个文件中不得有重复行1. 取出两个文件的并集(重复的行只保留一份)2. 取出两个文件的交集(只留下同时存在于两个文件中的文件)3. 删除交集,留下其他的行1. c ...

  4. 「WC2018即时战略」

    「WC2018即时战略」 题目描述 小 M 在玩一个即时战略 (Real Time Strategy) 游戏.不同于大多数同类游戏,这个游戏的地图是树形的.也就是说,地图可以用一个由 \(n\) 个结 ...

  5. [Usaco2015 Feb]Censoring --- AC自动机 + 栈

    bzoj 3940 Censoring 题目描述 FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S. 他有一个包含n个单词的列表,列表里的n个单词记为T1......Tn. ...

  6. WEB架构师成长之路 一

    一 .你必须学习面向对象的基础知识 1.降低软件开发的复杂度 2.提高软件开发的效率 3.提高软件质量:可维护性,可扩展性,可重用性等. 提高软件质量:可维护性,可扩展性,可重用性等,再具体点,就是高 ...

  7. [CC-CHEFGRPH]Time to Study Graphs with Chef

    [CC-CHEFGRPH]Time to Study Graphs with Chef 题目大意: 一个有向图可以分成\(n+2(n\le10^{12})\)层,第\(0\)层和第\(n+1\)层有\ ...

  8. iOS Core Animation 动画 入门学习(一)基础

    reference:https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide ...

  9. linux文件系统命令(6)---touch和mkdir

    一.目的 本文将介绍linux下新建文件或文件夹.删除文件或文件夹命令.         touch能够新建文件,mkdir用来新建文件夹.rm用来删除文件或文件夹.         本文将选取ubu ...

  10. .NET:异常处理的两条“黄金定律”,求批!

    背景 架构之处必须考虑:如何处理异常?如何定义自己的异常体系?本文为了强化这个概念而写. 异常处理的两条“黄金定律” 自己抄袭的两条规律: 异常不能穿过“边界类”. 异常不能在没有恢复的情况下“吞掉” ...