什么是柯里化?如何实现柯里化?

Curry

柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 — from wiki

为什么需要Curry?

理论基础: 在高中数学中学过lamda演算, 也很可能证明过多参数的函数都可以通过单参数的函数代替;同样在Haskell语法中多参的函数就是单参数的语法糖,同样在其他支持函数是一等公民的语言中,都可以使用单参数替换多参数的函数。

实践意义:我们抛弃陷入为主的观念,首先我们要思考 “为什么需要多参数?” ,在函数式编程的思维中思考,多参数只会让原本可以灵活组合的函数变得复杂。事实上们多参数的函数只是为了我们更加扁平化的定义和调用函数,但是多参数的函数在函数的复用上相对于单参数的函数有些局限性,例如在支持函数是一等公民的语言中,高阶函数对于多参的函数传入的处理相对于单参函数的处理会麻烦很多。

柯里化还践行了Point-free的思想, 可以更好应用于point-free的代码风格, 没有curry化的函数需要手动传入参数,这样使得我们需要同时关注数据和行为, 而非 point-free 的函数较难很难应用于函数的组合。

例如 我觉得这单参数可以更好利用在arr.map 、 filter函数中。

Point-free是什么?参考阮一峰的博客

curry使得函数具有更加细粒度方便组合;

实现curry

经常碰到的面试题就是add函数,add(1,2)()、 add(1)(2)()、add(1,2)(3,4)()

方法一: 使用function的对象的特性,把出入的参数存对象某个数组属性中,判断函数执行的时候是否没有参数,再选择执行,并清理函数这个属性

function curryAdd() {
  curryAdd.store = [...arguments, ...(curryAdd.store || [])];
  if (!arguments.length) {
    const temp = [...curryAdd.store];
    curryAdd.store = [];
    return temp.reduce((pre, curr) => pre + curr);
  }else {
    return curryAdd;
  }
}
复制代码

方法二: 利用闭包,函数执行之后依然要清理闭包中的变量

function curryAdd() {
  curryAdd.store = [...arguments, ...(curryAdd.store || [])];
  if (!arguments.length) {
    const temp = [...curryAdd.store];
    curryAdd.store = [];
    return temp.reduce((pre, curr) => pre + curr);
  }else {
    return curryAdd;
  }
}
复制代码

打印一下结果:

const Mres = curryAdd(1,2,3)(4,5)(6)()
console.log('----curry1');
console.log(Mres);
console.log(curryAdd(1)());
const res2 = curryAdd2(1,2,3)(4,5)(6)()
const res3 = curryAdd2(1)()
console.log('---curry2');
console.log(res2);
console.log(res3)
// ----curry1
// 21
// 1
// ---curry2
// 21
// 1
复制代码

如何把一个多参数的函数转换成curry化的函数呢?

例如:

function myCurry() {
  // ...
}
function addAll(a, b, c) {
  return a + b + c;
}

function joinName(firstName, lastName) {
  return firstName + ' ' + lastName
}

const currAddAll = myCurry(addAll)
const curryJoinName = myCurry(joinName)
console.log('-----my curry');
console.log(currAddAll(1)(2)(3));
console.log(curryJoinName('zhang', 'shuang'));
console.log(curryJoinName('zhang')('shuang'));
// -----my curry
// 6
// zhang shuang
// zhang shuang
复制代码

下面实现这个函数:

注意这里依然利用闭包的特性,在函数最终被执行的出口需要reset闭包,否则多次执行会有残余

function myCurry(fn) {
  let store = [];
  function resFn(...rest) {
    store = [...store, ...rest];
    if (store.length === fn.length) {
      const temp = [...store]
      store = [];
      return fn.apply(null, temp);
    }else {
      return resFn;
    }
  };
  return resFn;
} 
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享