2 回答
TA贡献1830条经验 获得超9个赞
您的代码与传感器无关。您对filter和 的定义m̀ap表明它使用普通的 JSfilter和map
const map = fn => arr => arr.map (fn),
const filter = fn => arr => arr.filter (fn),
const combo = compose(map(add1), filter(even));
combo(arr); ==> [2, 4]
发生的情况是初始数组被传递给mapwith add1,它将生成数组[2, 3, 4],然后它被传递给filterwitheven并[2, 4]创建一个新数组。
换能器也一样:
const arr = [1, 2, 3];
const add1 = n => n + 1;
const even = n => n% 2 === 0;
const compose = (...fns) => {
const [firstFunc, ...restFuncs] = fns.reverse();
return (...args) => restFuncs.reduce((acc, fn) => fn(acc), firstFunc(...args));
};
const mapping =
fn => join => (acc, e) => join(acc, fn(e));
const filtering =
isIncluded => join => (acc, e) => isIncluded(e) ? join(acc, e) : acc;
const transducer = compose(mapping(add1), filtering(even));
const arrayJoin = (acc, e) => ([...acc, e]);
const result = arr.reduce(transducer(arrayJoin), []);
console.log(result);
所以区别在于,当您将 传递join给换能器时,会发生这种情况:
mapping(add1)(filtering(even)(arrayAdd))
filtering是添加到某些集合的唯一步骤。当mapping调用join是filtering直接调用。这就是为什么签名(acc, e)在工作部分和join功能上是相同的。当代码运行时,添加和过滤同时完成,结果只有一个生成的数组,没有中间值。
TA贡献1851条经验 获得超5个赞
转换器利用了函数组合从 arity 中抽象出来的事实,即可以返回一个函数而不是“正常值”:
const comp = f => g => x => f(g(x));
const add = x => y => x + y;
const sqr = x => x * x;
const add9 = comp(add) (sqr) (3); // returns a lambda
console.log(
add9(6)); // 15
现在换能器本身很无聊:
reduce => acc => x => /* body is specific to the transducer at hand */
它只是一个需要 reducer(即组合其两个参数的二元函数)的闭包,然后可以直接输入到您最喜欢的 reduce 函数中。
我们来看看地图转换器:
const mapper = f => (reduce => acc => x =>
reduce(acc) (f(x)));
多余的括号只是说明了换能器的闭合。在这种情况下,它关闭了f我们的转换函数。接下来我们将应用它:
// map transducer
const mapper = f => reduce => acc => x =>
reduce(acc) (f(x));
// my favorite fold (reducing function)
const arrFold = alg => zero => xs => {
let acc = zero;
for (let i = 0; i < xs.length; i++)
acc = alg(acc) (xs[i], i);
return acc;
};
// reducer
const add = x => y => x + y;
// transformer
const sqr = x => x * x;
// MAIN
const main = arrFold(mapper(sqr) (add)) (0);
console.log(
main([1,2,3])); // 14
嗯,没有那么令人印象深刻,对吧?转换器的真正力量来自于它们与功能组合的结合:
// map transducer
const mapper = f => reduce => acc => x =>
reduce(acc) (f(x));
// filter transducer
const filterer = p => reduce => acc => x =>
p(x) ? reduce(acc) (x) : acc;
// my favorite fold (reducing function)
const arrFold = alg => zero => xs => {
let acc = zero;
for (let i = 0; i < xs.length; i++)
acc = alg(acc) (xs[i], i);
return acc;
};
// helpers
const add = x => y => x + y; // reducer
const sqr = x => x * x; // transformer
const isOdd = x => (x & 1) === 1; // predicate
const comp = f => g => x => f(g(x));
// MAIN
const main = arrFold(comp(filterer(isOdd)) (mapper(sqr)) (add)) (0);
console.log(
main([1,2,3])); // 10
尽管我们涉及到两个传感器,但只有一次遍历Array
. 此属性称为循环融合。由于换能器组合返回另一个函数,因此求值顺序相反,即从左到右,而函数组合通常从右到左。
可重用性是另一个优点。您只需定义一次转换器,并且可以将它们一次性用于所有可折叠数据类型。
还值得注意的transduce
是,这只是一个方便的功能,对理解概念并不重要。
关于换能器,差不多就是这样。
添加回答
举报