【问题标题】:How to implement infinite currying sum values with a callback function with result in javascript?如何在javascript中使用带有结果的回调函数实现无限柯里化总和值?
【发布时间】:2023-03-16 01:12:02
【问题描述】:

我有一个测试,我需要在这种情况下实现一个称为 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

【问题讨论】:

  • 这真的是一个 TypeScript 问题吗?我在这里根本看不到任何打字
  • this 是否满足您的需求?您是否需要能够重复使用部分结果?
  • 是的,它也满足了。感谢您的回复。
  • 你明白!a ? …b ? …在你找到的代码中做了什么吗?
  • 是的,因为该代码是为我完成的。这是我最初的解决方案。

标签: javascript ecmascript-6 closures higher-order-functions currying


【解决方案1】:

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

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 参数被装箱并再次拆箱。

【讨论】:

  • 那么sum() 的输出有状态吗?这意味着const foo = sum(0); foo(100)(x => console.log(x)); /* 100 */ foo(1)(x => console.log(x)); 记录101 而不是1。我想知道这是否是他们想要的。 (我猜是因为它被接受了)
  • 是的,@jcalz,说得好。添加了一个通过 this-argument 传递总数的版本。
  • "您可以使用this 参数" - 为什么不直接使用普通参数?
  • const sum = (function makeInner(total) { return function(arg) { if (typeof arg == 'function') arg(total) else if (typeof arg == 'number') return makeInner(total + arg); }; })(0);
【解决方案2】:

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

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

通过这种方式,您可以设置一个连续的柯里化执行链,当函数作为参数传递时终止。

实际的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() 的定义已减少。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 2018-07-25
    • 2017-05-16
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    相关资源
    最近更新 更多