bibi7 / fe-daily-increase

一个记录开发日常和奇奇怪怪的点的repo
MIT License
5 stars 0 forks source link

currying #45

Open bibi7 opened 5 years ago

bibi7 commented 5 years ago

函数柯里化又叫部分求值,维基百科中对柯里化 (Currying) 的定义为:

在数学和计算机科学中,柯里化是一种将使用多个参数的函数转换成一系列使用一个参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

简单来说,柯里化其实就是一个参数收集的过程,将每一次传入的参数收集起来,然后在最里层再进行处理。

所以一个合格的柯里化函数需要这么几点:

  1. 当参数未收集完毕的时候继续收集参数
  2. 当参数收集完毕后调用方法
const curring = (fn) => {
  const args = []
  return function InnerFn(...rest) {
    if (rest.length === 0) {
      return fn(...args)
    }
    args.push(...rest)
    return InnerFn
  }
}

const add = (...result) => result.reduce((a, b) => a + b)
const sum = curring(add)
sum(1)
sum(2)
sum(3)(4)
sum(5,6)(7)
sum() //28

其实上文所实现的功能就类似于延迟计算,但是有个缺点:

  1. 最后需要多调用一次,也就是类似于sum(1, 2, 3)(4, 5)(6)()

另一种更通用的柯里化:

const currying = (fn) => {
  return inner => (...args) => 
    args.length >= fn.length
      ? fn(...args)
      : (...arg) => inner(...args, ...arg)
}

const fn = currying(function(a, b, c) {
    console.log([a, b, c]);
});

fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]

fnn('1',)
//(...arg) => inner(...args, ...arg)
fnn('1','2')
//(...arg) => inner(...args, ...arg)
fnn('1','2')(3)
//["1", "2", 3]

这样我们就实现了一个通用柯里化,实现原理就是「用闭包把传入参数保存起来,当传入参数的数量足够执行函数时,就开始执行函数」。比刚才的延迟计算类型的柯里化更完善一点。

但是我一直很疑惑一点,后者其实会被初始函数的形参个数限定死,万一碰到初始函数形参个数不定的呢?(:з」∠)