# 附录 A：Transducing（下）

### 组合柯里化

``````var x = curriedMapReducer( strUppercase );
var y = curriedFilterReducer( isLongEnough );
var z = curriedFilterReducer( isShortEnough );``````

``````var upperReducer = x( listCombination );
var longEnoughReducer = y( listCombination );
var shortEnoughReducer = z( listCombination );``````

``````function reducer(list,val) {
if (isLongEnough( val )) return z( list, val );
return list;
}``````

``````var shortEnoughReducer = z( listCombination );
var longAndShortEnoughReducer = y( shortEnoughReducer );``````

``````// shortEnoughReducer, from z(..):
function reducer(list,val) {
if (isShortEnough( val )) return listCombination( list, val );
return list;
}

// longAndShortEnoughReducer, from y(..):
function reducer(list,val) {
if (isLongEnough( val )) return shortEnoughReducer( list, val );
return list;
}``````

``````longAndShortEnoughReducer( [], "nope" );
// []

longAndShortEnoughReducer( [], "hello" );
// ["hello"]

longAndShortEnoughReducer( [], "hello world" );
// []``````

`longAndShortEnoughReducer(..)` 会过滤出不够长且不够短的值，它在同一步骤中执行这两个过滤。这是一个组合 reducer！

``````var longAndShortEnoughReducer = y( z( listCombination) );
var upperLongAndShortEnoughReducer = x( longAndShortEnoughReducer );``````

``````// upperLongAndShortEnoughReducer:
function reducer(list,val) {
return longAndShortEnoughReducer( list, strUppercase( val ) );
}``````

``````upperLongAndShortEnoughReducer( [], "nope" );
// []

upperLongAndShortEnoughReducer( [], "hello" );
// ["HELLO"]

upperLongAndShortEnoughReducer( [], "hello world" );
// []``````

``````var x = curriedMapReducer( strUppercase );
var y = curriedFilterReducer( isLongEnough );
var z = curriedFilterReducer( isShortEnough );

var upperLongAndShortEnoughReducer = x( y( z( listCombination ) ) );

words.reduce( upperLongAndShortEnoughReducer, [] );
// ["WRITTEN","SOMETHING"]``````

`x(y(z( .. )))` 是一个组合。我们可以直接跳过中间的 `x` / `y` / `z` 变量名，直接这么表示该组合：

``````var composition = compose(
curriedMapReducer( strUppercase ),
curriedFilterReducer( isLongEnough ),
curriedFilterReducer( isShortEnough )
);

var upperLongAndShortEnoughReducer = composition( listCombination );

words.reduce( upperLongAndShortEnoughReducer, [] );
// ["WRITTEN","SOMETHING"]``````

1. `listCombination(..)` 作为组合函数传入，构造 `isShortEnough(..)` 过滤器的 reducer。
2. 然后，所得到的 reducer 函数作为组合函数传入，继续构造 `isShortEnough(..)` 过滤器的 reducer。
3. 最后，所得到的 reducer 函数作为组合函数传入，构造 `strUppercase(..)` 映射的 reducer。

// TODO：检查 transducer 是产生 reducer 还是它本身就是 reducer

``````var transducer = compose(
curriedMapReducer( strUppercase ),
curriedFilterReducer( isLongEnough ),
curriedFilterReducer( isShortEnough )
);

words
.reduce( transducer( listCombination ), [] );
// ["WRITTEN","SOMETHING"]``````

#### 列表组合：纯与不纯

``````function listCombination(list,val) {
return list.concat( [val] );
}``````

``````function listCombination(list,val) {
list.push( val );
return list;
}``````

`listCombination(..)` 不是我们完全有交互的函数。我们不直接在程序中的任何地方使用它，而只是在 transducing 的过程中使用它。

`listCombination(..)` 更多的是转换的内部实现细节。实际上，它通常由 transducing 库提供！而不是你的程序中进行交互的顶层方法。

### 可选的组合

``````words
.reduce( transducer( listCombination ), [] )
.reduce( strConcat, "" );
// 写点什么``````

``````function strConcat(str1,str2) { return str1 + str2; }

function listCombination(list,val) { list.push( val ); return list; }``````

``````words.reduce( transducer( strConcat ), "" );
// 写点什么``````

Boom！ 这就是 transducing。

## 最后

``````var transduceMap = curry( function mapReducer(mapperFn,combinationFn){
return function reducer(list,v){
return combinationFn( list, mapperFn( v ) );
};
} );

var transduceFilter = curry( function filterReducer(predicateFn,combinationFn){
return function reducer(list,v){
if (predicateFn( v )) return combinationFn( list, v );
return list;
};
} );``````

``````var transducer = compose(
transduceMap( strUppercase ),
transduceFilter( isLongEnough ),
transduceFilter( isShortEnough )
);``````

`transducer(..)` 仍然需要一个组合函数（如 `listCombination(..)``strConcat(..)`）来产生一个传递给 `reduce(..)` （连同初始值）的 transduce-reducer 函数。

``````function transduce(transducer,combinationFn,initialValue,list) {
var reducer = transducer( combinationFn );
return list.reduce( reducer, initialValue );
}``````

``````var transducer = compose(
transduceMap( strUppercase ),
transduceFilter( isLongEnough ),
transduceFilter( isShortEnough )
);

transduce( transducer, listCombination, [], words );
// ["WRITTEN","SOMETHING"]

transduce( transducer, strConcat, "", words );
// 写点什么``````

### Transducers.js

``````var transformer = transducers.comp(
transducers.map( strUppercase ),
transducers.filter( isLongEnough ),
transducers.filter( isShortEnough )
);

transducers.transduce( transformer, listCombination, [], words );
// ["WRITTEN","SOMETHING"]

transducers.transduce( transformer, strConcat, "", words );
// WRITTENSOMETHING``````

`transducers.map(..)``transducers.filter(..)` 是特殊的辅助函数，可以将常规的断言函数或映射函数转换成适用于产生特殊变换对象的函数（里面包含了 reducer 函数）；这个库使用这些变换对象进行转换。此转换对象抽象的额外功能超出了我们将要探索的内容，请参阅该库的文档以获取更多信息。

``````words.reduce(
transducers.toFn( transformer, strConcat ),
""
);
// WRITTENSOMETHING``````

`into(..)` 是另一个提供的辅助函数，它根据指定的空/初始值的类型自动选择默认的组合函数：

``````transducers.into( [], transformer, words );
// ["WRITTEN","SOMETHING"]

transducers.into( "", transformer, words );
// WRITTENSOMETHING``````

## 总结

Transduce 就是通过减少来转换。更具体点，transduer 是可组合的 reducer。

transducing 主要提高性能，如果在延迟序列（异步 observables）中使用，则这一点尤为明显。

【上一章】翻译连载 | 附录 A：Transducing（上）－《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。

iKcamp官网：https://www.ikcamp.com

《iKcamp出品｜全网最新｜微信小程序｜基于最新版1.0开发者工具之初中级培训教程分享》
《iKcamp出品｜基于Koa2搭建Node.js实战项目教程》