[Transducer] Step by Step to build a simple transducer
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
- 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!
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;
};
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的更多相关文章
- Build step 'Execute shell' marked build as failure解决
今天jenkins构建时运行脚本报错如下: Build step 'Execute shell' marked build as failure 脚本没问题后来看了下原因是磁盘空间不足导致报错,清除下 ...
- Jenkins Build step 'Execute shell' marked build as failure
问题出现: Jenkins一直都构建成功,今天突然报错:Jenkins Build step 'Execute shell' marked build as failure 问题原因: By defa ...
- [转]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 ...
- 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 ...
- 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 ...
- 课程四(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 ...
- Convolutional Neural Networks: Step by Step
Andrew Ng deeplearning courese-4:Convolutional Neural Network Convolutional Neural Networks: Step by ...
- 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 ...
- 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 ...
随机推荐
- 【Java虚拟机】JVM学习笔记之GC
JVM学习笔记二之GC GC即垃圾回收,在C++中垃圾回收由程序员自己来做,例如可以用free和delete来回收对象.而在Java中,JVM替程序员来执行垃圾回收的工作,下面看看GC的详细原理和执行 ...
- linux——(6)vim与vi
概念:vi与vim的区别 vi是一款老式的文字处理软件,不过现在依然广泛使用,所有的UnixLike系统都会内置vi文本编辑器. vim可以看出vi的升级版,不过vi更像是一个程序开发工具,功能也比v ...
- 【BZOJ 1272】 1272: [BeiJingWc2008]Gate Of Babylon (容斥原理+卢卡斯定理)
1272: [BeiJingWc2008]Gate Of Babylon Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 254 Solved: 12 ...
- 安卓 自定义ViewGroup
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 指定的 布局参数 在计算时候方法 中 计算 所有 子视图的 宽高, 然后根据这些 计算出 ...
- BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
- BZOJ1509 [NOI2003]逃学的小孩 树型DP
题目: 分析: 首先明确我们是要求 min(dist[C][A],dist[C][B])+dist[A][B]. 我们把C当成树根,第一我们可以发现min里面取dist[C][A]或者dist[C][ ...
- 【点分治】【路径小于等于k的条数】【路径恰好等于k是否存在】
POJ1741:Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 29574 Accepted: 9915 Des ...
- Hive集合数据类型
Hive的列除了支持基本的数据类型外,还支持使用Struct.Map和Array三种集合数据类型. 假设某表有如下一行,我们用JSON格式来表示其数据结构.在Hive下访问的格式为 { "n ...
- mysql 绿色版安装
1. 下载MySql5.6.10GA解压缩版,这就不多说也不上图了,下不到或者下好之后不知道如何解压的接下去的文章也没什么好多看的. 2. 解压好之后进入根目录是这样个情况(本人使用的是MySql5. ...
- DropdownList 赋初始值问题
网上查了这样的代码 虽然是可以用.但是会点击多次会出现”“ dropdownList不能选多个值的问题“ private void initdroplistitemlirun(string c_Bus ...