#30 curry 函数


  • 0
    administrators

    函数式编程当中有一个非常重要的概念就是 函数柯里化。一个接受 任意多个参数 的函数,如果执行的时候传入的参数不足,那么它会返回新的函数,新的函数会接受剩余的参数,直到所有参数都传入才执行操作。这种技术就叫柯里化。请你完成 curry 函数,它可以把任意的函数进行柯里化,效果如下:

    const f = (a, b, c d) => { ... }
    const curried = curry(f)
    
    curried(a, b, c, d)
    curried(a, b, c)(d)
    curried(a)(b, c, d)
    curried(a, b)(c, d)
    curried(a)(b, c)(d)
    curried(a)(b)(c, d)
    curried(a, b)(c)(d)
    // ...
    // 这些函数执行结果都一样
    
    // 经典加法例子
    const add = curry((a, b) => a + b)
    const add1 = add(1)
    
    add1(1) // => 2
    add1(2) // => 3
    add1(3) // => 4
    

    注意,传给 curry 的函数可能会有任意多个参数。


  • 4

    再分享一段1~2行实现的代码。

    const curry = ( f, arr = []) => (...args) => ( a => a.length === f.length ? f(...a) : curry(f, a))([...arr, ...args]);
    

    只是想说ES6真的是个好东西...


  • 0

    @ackerMan 怎么没有点赞这个功能,手动点赞


  • 0
    管理员

    “结果不正确”,大哈哥帮忙看看。。

    const curry = f => {
      let arr = [];
      const fn = (...args) => {
        arr.push(...args)
        return arr.length === f.length? f(...arr): fn
      }
      return fn
    }
    

  • 0
    administrators

    @陈小俊

    下面的例子要跑通:

    const add = curry((a, b) => a + b)
    const add1 = add(1)
    
    add1(1) // => 2
    add1(2) // => 3
    add1(3) // => 4
    ...
    

  • 0
    管理员

    楼上的一行代码太牛了,鄙人愚钝一下无法理解,还是自己总结了下,对比了下才看懂:
    es5写法:

    var curry = function curry(f) {
      //获取curry的参数,如果第二个参数不存在,则创建一个空数组
      var arr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
      return function f1() {
        //获取当前函数的参数
        for (var len = arguments.length, args = Array(len), i = 0; i < len; i++) {
          args[i] = arguments[i];
        }
        //如果参数没有传完,合并arr和args,递归调用curry
        //f2函数其实是递归调用的终止条件,如果已经传完参数,执行函数并终止,否则递归curry
        return function f2(a) {
          return a.length === f.length ? f.apply(null, a) : curry(f, a);
        }([].concat(arr, args));//这种写法是将arr和args合并后作为f2函数的参数
      };
    };
    

    es6:

    const curry = (f, arr = []) => {
      return (...args) => {
        return (a) => {
          return a.length === f.length ? f(a) : curry(f, a);
        }([...arr, ...args]);
      };
    };
    

    最后自己总结了下:函数柯里化Currying


  • 0

    @陈小俊#30 curry 函数 中说:

    return a.length === f.length ? f(a) : curry(f, a);

    这里写错了吧... a 是个数组,要这样调用才行吧... f.apply(null, a)


  • 0

    @陈小俊#30 curry 函数 中说:

    //获取当前函数的参数
    for (var len = arguments.length, args = Array(len), i = 0; i < len; i++) {
    args[i] = arguments[i];
    }

    而且这段也太啰嗦了...

    其实就是这个吧...

    var args = [].slice.call(arguments)
    

    完整代码...

    var curry = function curry(fn) {
      var arr = arguments[1]
        ? arguments[1]
        : []
    
      return function f1() {
        var args = [].slice.call(arguments)
    
        return function f2(arg) {
          return arg.length === fn.length
            ? fn.apply(null, arg)
            : curry(fn, arg)
        }(arr.concat(args))
      }
    }
    

  • 0
    管理员

    @steveyoung 对,这里搞错了,谢谢指出


  • 0

    const curry = (fn) => {
      const paramLen = fn.length
      const args = []
      const restFn =  (...rest) => {
        rest.map((arg) => {args.push(arg)})
        if(args.length < paramLen) {
          return restFn
        } else {
          const result = fn.apply(null, args)
          args.pop()
          return result
        }
      }
      return restFn
    }
    

    这是我写的代码,可以通过题目中的测试

    但是提交的时候总是提示:fn is not a function

    这是怎么回事啊


  • 1

    const curry = (f, args1 = []) => (...args2) => {
      const args = [ ...args1, ...args2 ]
      return f.length === args.length
      ? f(...args)
      : curry(f, args)
    }
    

    和一行代码的那个类似,为了可读性把合并参数和三目运算拆开写了。没有用IIFE,应该更好理解了。


  • 0

    为什么不正确?题目显示
    let curry = (f, arr = []) => {
    return (...args) => { // ...rest参数是一个数组
    return ((a) => {
    return a.length === f.length ? f(a) : curry(f, a)
    })([...arr, ...args])
    }
    }


  • 0

    return a.length === f.length ? f(a) : curry(f, a)

    ->

    return a.length === f.length ? f(...a) : curry(f, a)


登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待