【问题标题】:Writing a unary function chainer, TypeError on codewars but no error on repl.it?编写一元函数链接器,代码战上的 TypeError 但 repl.it 上没有错误?
【发布时间】:2016-10-07 07:37:18
【问题描述】:

我在代码大战中研究了这个问题一段时间,并使用 repl.it 对其进行了测试。它是一个简单的一元函数链接器,但它仅适用于 repl.it,而 codewars 在给出此代码时会给我一个 TypeError:

function chained(functions) {
  var funcs = Array.prototype.slice.call(arguments);

  return function (value){

    var finalValue = funcs.reduce(function(prevVal, currFunc){

        return currFunc(prevVal);

    }, value);

    return finalValue;
  }
}

它告诉我 currFunc 不是一个函数,但是使用以下测试代码我在 repl.it 中运行时得到了正确的答案:

function f1(x){ return x*2 }
function f2(x){ return x+2 }
function f3(x){ return Math.pow(x,2) }
console.log(chained(f1,f2,f3)(0));

它不是代码战中的函数有什么原因吗?

【问题讨论】:

  • 确切的错误是什么?
  • This: TypeError: currFunc is not a function at Array.reduce at doFunc at Object.handleError at ContextifyScript.Script.runInThisContext at Object.exports.runInThisContext
  • 您确定 codewars 正在运行您发布的代码吗?

标签: javascript functional-programming chaining declarative-programming


【解决方案1】:

我不得不查找关于代码战的测试。他们给你这个样板......

function chained(functions) {
  //FIXME
}

查看测试,您可以看到函数正在数组中传递...

Test.assertEquals( chained([f1,f2,f3])(0), 4 )
Test.assertEquals( chained([f1,f2,f3])(2), 36 )
Test.assertEquals( chained([f3,f2,f1])(2), 12 )

你犯的错误是……

var funcs = Array.prototype.slice.call(arguments);

...只有在chained 被这样调用时才有效...

chained(f1,f2,f3)

否则您的代码可以正常工作并通过代码战的所有测试。这是完整的变化...

function chained(functions) {
  var funcs = Array.prototype.slice.call(arguments);
  return function (value){
    var finalValue = funcsfunctions.reduce(function(prevVal, currFunc){
      return currFunc(prevVal);
    }, value);
    return finalValue;
  }
}

最后,这是我的解决方案^_^

const id = x => x;
const uncurry = f => (x,y) => f (x) (y);
const rcomp = f => g => x => g (f (x));
const chained = fs => fs.reduce(uncurry(rcomp), id);

【讨论】:

  • 谢谢,有道理!
【解决方案2】:

虽然@naomik 的解决方案是正确答案并且应该被接受,但我只是想分享一个使用老式 ES3 的替代解决方案:

function chained(functions) {
    return function(x) {
        var fs = functions, i = fs.length, y = x;
        while (i > 0) y = fs[--i](y);
        return y;
    };
}

这只是为了表明在这种特殊情况下您实际上并不需要使用reduce 来编写简洁的代码。此外,使用while 循环在性能方面比使用reduce 更好。最后,这段代码也很好理解。您无需费力地减少 iduncurry(rcomp) 即可了解如何通过折叠函数实现链接。

【讨论】:

    【解决方案3】:

    在 ES6 中也有同样的想法。 Fun 是一个函数数组。

    const chained = fun => {
        return input => {
            return fun.reduce((acc, currentFun) => currentFun(acc), input);
        }
    };
    

    还有一些更难读但漂亮的现代 JS 版本:

    const chained = fun => input => fun.reduce((acc, currentFun) => currentFun(acc), input);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-08
      • 2021-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多