[a,b].reduce(f,x)代码为[a,b.reduce(f)使用基于换能器/CPS的功能参考



在我之前的Quesion:中

从无阵列的函数链中提取数据

@Aadit M Shah给了我惊人的解决方案如下:

https://stackoverflow.com/a/51420884/6440264

给定像A(a)(b)(f)这样的表达式,其中f是一个函数,不可能知道f是否应该添加到列表中,或者它是否是约简函数。因此,我将描述如何编写类似A(a)(b)(f, x)的表达式,它等效于[a, b].reduce(f, x)。这使我们能够根据您提供的参数数量来区分列表何时结束:

const L = g => function (x, a) {
switch (arguments.length) {
case 1: return L(k => g((f, a) => k(f, f(a, x))));
case 2: return g((f, a) => a)(x, a);
}
};
const A = L(x => x);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y, 0));        // 15
console.log(xs((x, y) => x * y, 1));        // 120
console.log(xs((a, x) => a.concat(x), [])); // [1,2,3,4,5]

由于连续性,它可以工作。每次我们添加一个新元素,我们都会累积一个CPS函数。每个CPS函数调用上一个CPS函数,从而创建一个CPS功能链。当我们给这个CPS函数链一个基本函数时,它会展开这个链,并允许我们减少它。在换能器和透镜后面也是一样的想法

我还有2个问题。

  1. 为了区分还原函数,我考虑了一些使用反射的自定义打字机制,但为了关注这个问题,到目前为止,我只想简单地应用

    const isReducer=f=>(f=="函数"的类型(;

  2. 提供初始值的要求有折叠/减少的限制,例如,不可能为减少的二进制操作(如(提供初始值

    常量头=(a,b(=>a;const-tail=(a,b(=>b;

(除非手动提供第一个/最后一个值,否则运行代码毫无意义(理论上,每一个二进制运算都有一个恒等式值,但有些东西是不可能提供的。唯一的方法是抽象为恒等式。

话虽如此,我无法将提供的代码重构为单个参数和函数的reducer类型,并将默认值作为序列的初始值。

你能提供重构后的代码吗?此外,对于该示例,换能器/CPS的任何信息都是值得赞赏的。

如果不提供初始值,则会损失大量功率。例如,您将无法将列表转换为数组。这是因为返回类型必须与列表中元素的类型相匹配。考虑:

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f a []     = a
foldl f a (x:xs) = foldl f (f a x) xs
foldl1 :: (a -> a -> a) -> [a] -> a
foldl1 f (x:xs) = foldl f x xs

如您所见,foldl的返回类型可以是独立于类型a的任何类型b。但是,foldl1的返回类型被强制为a。因此,如果你有一个列表A(1)(2)(3)(4)(5),那么当你折叠这个列表时,结果必然是一个数字。

您可以通过执行类似A(1)(2)(3)(4)(5)(concat2)的操作来摆脱它,其中const concat2 = (x, y) => [].concat(x, y)是因为JavaScript不是强类型语言。然而,这是不一致的,因为A([1,2,3])([4,5,6])([7,8,9])(concat2)的求值结果是[1,2,3,4,5,6,7,8,9]而不是[[1,2,3],[4,5,6],[7,8,9]]。如果没有初始值,我看不出有任何方法可以将第二个列表转换为数组,同时保留其结构。


尽管如此,如果你仍然想这样做,那么你几乎不需要改变。请注意,foldl1只是将工作委派给foldl。因此,我们只需要将列表的第一个元素与其他元素分开,并将其用作累加器的初始值:

const L = g => a => x => typeof x !== "function" ?
L((f, a) => f(g(f, a), x))(a) :
g(x, a);
const A = L((f, a) => a);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y)); // 15
console.log(xs((x, y) => x * y)); // 120

最后,如果你真的想学习函数编程和延续,那么我建议你阅读SICP(计算机程序的结构和解释(或HtDP(如何设计程序(。HtDP通常被认为对初学者更友好。然而,我强烈建议阅读SICP。

最新更新