如何使用结果为 javascript 的回调函数实现无限柯里化总和值?

How to implement infinite currying sum values with a callback function with result in javascript?

我有一个测试,我需要在这种情况下实现一个名为 sum 的高阶函数,它满足以下要求:

sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7

我做了一个函数,以便通过递归获得无限柯里化,但我对回调函数有点迷茫。

let sum = a => !a ? 0 : b => b ? sum(a+b) : a
console.log(sum()) -> 0
console.log(sum(1)()) -> 1
console.log(sum(1)(2)()) -> 3
console.log(sum(1)(2)(4)()) -> 7

使用闭包来累加总和。当内部函数检测到参数是一个函数时,它将调用带有总和的回调。否则它会 return 自己调整和后:

function sum(arg) {
    let total = 0;
    
    function inner(arg) {
        if (typeof arg === "function") {
            arg(total);
        } else {
            total += arg;
            return inner;
        }
    }
    
    return inner(arg);
}

sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7

如果函数不打算保持状态,则可以使用 this 参数传递总数:

"use strict";
function sum(arg) {
    function inner(arg) {
        if (typeof arg === "function") {
            arg(+this);
        } else {
            return inner.bind(this + arg);
        }
    }
    
    return inner.call(0, arg);
}

sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7

const foo = sum(0); 
foo(100)(console.log); // 100 
foo(1)(console.log); // 1

此处建议使用严格模式,但在草率模式下也可以。在这种情况下,this 参数会再次装箱和拆箱。

为简单起见,您可以有一个接受两个参数的辅助函数。第一个参数是一个数字。第二个参数是一个数字或函数,根据类型它会做不同的事情:

  • 当它是一个函数时,它将执行它并将第一个参数传递给它。
  • 当它是一个数字时,它会将两个参数相加并将其作为助手的第一个参数传递。下一次,第一个参数将包含新的总数。

通过这种方式,您可以建立一个连续的 curried 执行链,当函数作为参数传递时该链会终止。

实际的 sum() 函数可以使用助手并通过将第一个参数设置为 0 来初始化链的开始 - neutral element 用于加法运算:

const helper = total => arg => {
  if (typeof arg === "function")
    arg(total);
  else if (typeof arg === "number")
    return helper(total + arg);
  else
    throw new Error("invalid argument");
}

const sum = x => 
  helper(0)(x);

sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7

为简单起见,helper() 函数已柯里化。


这里有一个更简洁的版本:

  • 假定只会传入数字或函数。
  • sum() 的定义已减少 eta。

const helper = total => arg => 
  (typeof arg === "function") 
    ? arg(total)
    : helper(total + arg);
  
const sum = helper(0);

sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7