Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

理解「函数柯里化」 #10

Open
heycn opened this issue May 11, 2023 · 0 comments
Open

理解「函数柯里化」 #10

heycn opened this issue May 11, 2023 · 0 comments

Comments

@heycn
Copy link
Owner

heycn commented May 11, 2023

如果没有接受函数式的一整套理论,就没有必要用柯里化

柯里化 Currying:让所有函数只接受一个参数

有什么意义?

我们把一个只接受一个参数的函数叫作「单参数函数」,基于这种函数,已经衍生出非常多的理论知识,而且是关于数学方面的,跟编程关系不大

λ演算 —— lambda演算

假设一个函数只支持一个参数

那么支持接受两个参数呢?

  1. 使用对象
  2. 使用闭包

一般来说,在函数式编程中,不使用对象,而是使用闭包,因为 —— 对象是穷人的闭包
如果不理解上面这句话,可以看下我写过的一篇博客对象是穷人的闭包,闭包是穷人的对象

我们有闭包了,就不需要使用对象

使用对象

const add = ({a, b}) => a + b
add({a: 1, b: 2})

上面这种方式在函数式编程中,特别的傻

使用闭包

const add = a => b => a + b
add(1)(2)

如果没见过上面这种写法,是不是看不太习惯?或者会疑问:闭包在哪里呢?
请继续往下看:

// 以上的代码,基本等价与下面的代码
add = function(a) {
  return function(b) {
    return a + b // 这个 a 就是和这个函数形成了闭包
  }
}
add(1)(2)

但是如果只写过 JS 的人,会感觉有点不方便对不对?

没错,如果没有接受过函数式的一整套理论,你会觉得这就是在耍花招,没什么用
但是你如果接受过一系列函数式的东西,你就会觉得柯里化是非常重要的部分,如果没学过,那就没必要用柯里化

柯里化一个函数

初级

请把三参数函数 add(1,2,3) 变成 curriedAdd(1)(2)(3) 形式:

const curriedAdd =
  a =>
    b =>
      c =>
        add(a, b, c)

完毕,非常的简单。

升级

假设:

  • addTwo 接受两个参数
  • addThree 接受三个参数
  • addFour 接受四个参数
  • 如何写出一个 currify 函数,使得他们分别接受 2、3、4 次参数,如:
    • currify(addTow)(1)(2) // 3
    • currify(addThree)(1)(2)(3) // 6
    • currify(addFour)(1)(2)(3)(4) // 10

也就是说,currify 函数能将任意接受固定个参数的函数,变成单一参数的函数

const currify = (fn, params = []) => {
  return (arg) => {
    const newParams = params.concat(arg)
    if(newParams.length === fn.length) {
      return fn(...newParams)
    } else {
      return currify(fn, newParams)
    }
  }
}

const addTwo = (a, b) => a + b

再升级

我想支持 currify(addFour)(1)(2,3)(4) // 10

那么需要这么改写

const currify = (fn, params = []) => {
- return (arg) => {
+ return (...args) => {
-   const newParams = params.concat(arg)
-   if(newParams.length === fn.length) {
+   if(params.length + args.length === fn.length) {
-     return fn(...newParams)
+     return fn(...params, ...args)
    } else {
-     return currify(fn, newParams)
+     return currify(fn, [...params, ...args])
    }
  }
}

最终简化

const currify = (fn, params = []) => 
  (...args) =>
    params.length + args.length === fn.length
      ? fn(...params, ...args)
      : currify(fn, [...params, ...args])

这样,是不是对「柯里化函数」有一点点理解了呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant