前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >为什么我要说:柯里化 == 闭包+递归?

为什么我要说:柯里化 == 闭包+递归?

作者头像
掘金安东尼
发布于 2022-09-19 02:44:26
发布于 2022-09-19 02:44:26
28600
代码可运行
举报
文章被收录于专栏:掘金安东尼掘金安东尼
运行总次数:0
代码可运行

theme: smartblue

柯里化是 JS 高程中不可或缺的重心,本篇带你来冲一冲它!!


我们不妨以两数相加为例子,递进说明。

我们通常是这样写一个函数来求得 两数相加 的值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function sum(a,b){
    console.log(a+b)
}
sum(1,2)

这样写一点毛病没有!

不过呢?问题总会在发展中产生,产品经理又要加一个值,需求:三数相加

咱通常来说,第一时间,就在原基础上,直接再加一个参数就是了;

于是,修改后像是这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function sum(a,b,c){
    console.log(a+b+c)
}
sum(1,2,3)

问:这样写,有毛病吗??

答:太有毛病了!

这样一改,既违反了:“开闭原则”、又违反了:“单一职责原则”。

为不太熟悉设计原则的小伙伴们,简单解释下:

  • 什么是“开闭原则”?即:我们编程中要尽可能的避免直接修改函数、类或模块,而是要在原有基础上拓展它;
  • 什么是“单一职责原则”?即:每个函数、类或模块,应该只负责一个单一的功能;

首先,咱修改了 sum 函数的传参以及内部的调用 ⇒ 则违反“开闭原则”

其次,sum 函数本来只负责两数相加,修改后,它又负责三数相加,职责已经发生了变化 ⇒ 则违反 “单一职责原则”;

如果正规按照单一责任来写,应该是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 负责两数相加
function sum2(a,b){
    console.log(a+b)
}

// 负责三数相加
function sum3(a,b,c){
    console.log(a+b+c)
}

事实上,是不可能这样去写的,因为如果有一万个数相加,得写一万个函数。

加法只有一个!! 不管你最终要加几个值,总是要一个加一个。

于是乎,我们设想,能不能写一个这样的函数:它的功能,就是“加”,参数跟几个,我就加几个。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 负责“加法”,
function addCurry(){
    ...
    ...
    ...
}

addCurry(1)(2) // 两数相加
addCurry(1)(2)(3) // 三数相加
...
addCurry(1)(2)(3)...(n) // n 数相加

没错,这个函数就是:柯里化!!(或者说这个过程叫柯里化,这个思想叫柯里化,本瓜认为这里不需要太死扣定义)

接着,我们一步步来试试,它会是怎样构成的?

为了能够实现一个加一个,即存储参数的目的,我们想一想,还有什么法宝?

没错,JS 奥义:闭包!

其实,本瓜时常想,闭包的终极秘密是什么?最后将其理解为 4 个金光闪闪的大字:延迟处理

什么意思?简单解释下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function directHandle(a,b){
    console.log("直接处理",a,b)
}

directHandle(111,222)

// 直接处理 111 222

function delayHandle(a){
    return function(b){
         console.log("延迟处理",a,b)
    }
}

delayHandle(111)

// ƒ (b){
//	    console.log("延迟处理",a,b)
//	}

如上 delayHandle(111) 不像 directHandle(111,222) 直接打印值,而是先返回一个函数 f(b);111 也被临时保存了,delayHandle(111)(222),则得到相同的输出。这就是:延迟处理的思想。

另外补一句:延迟处理是函数式编程的精华所在,在不能保证每个函数都是纯函数的前提下,在管道处理的最后,再进行处理,能最大程度的保证减少副作用。也就是 Monad 思想,此处不做展开。

言归正传,于是乎,我们借用闭包来实现最初版的柯里化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 两数相加
function addCurry(a){
    return function(b){
            console.log(a+b)
    }
}

addCurry(1)(2)

// 三数相加
function addCurry(a){
    return function(b){
        return function(c){
             console.log(a+b+c)
        }
    }
}

addCurry(1)(2)(3)

写两个闭包的过程,聪明的你一定就明白了,这样一直写下去,不就是递归吗?!

于是乎,我们知道,当参数是 n 个的时候,需要递归 n-1 次 return function

于是乎,addCurry 写法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 let arr = []
 function addCurry() {
     let arg = Array.prototype.slice.call(arguments); // 递归获取后续参数
     arr = arr.concat(arg);
      if (arg.length === 0) { // 如果参数为空,则判断递归结束
          return arr.reduce((a,b)=>{return a+b}) // 求和
      } else {
          return addCurry;
      }
  }

addCurry(1)(2)(3)()

OK,至此,,大功告成!!

以上,用最简单的代码解释了 —— 为什么我说:柯里化 == 闭包+递归 ?

柯里化是一种思想,上面的 addCurry 可以说是最简单的一种实践。在函数式编程中,Curry 更是大放异彩,比如 compose(fn1)(fn2)(fn3)…(fnN)(args) 等等。

如果以后有人再问你柯里化,可以往这个方向上答。。。

OK,以上便是本篇分享。 觉得不错点个赞吧👍👍👍,您的鼓励,我的动力,坚持原创质量好文~~ 欢迎评论留言 我是掘金安东尼,输出暴露输入,技术洞见生活。再会吧~~ 👋👋👋

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
全排列 next_permutation的使用
给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。 我们假设对于小写字母有'a' < 'b' < ... < 'y' < 'z',而且给定的字符串中的字母已经按照从小到大的顺序排列。
喜欢ctrl的cxk
2019/11/07
5550
排列类算法问题大总结全排列分析带重复元素的全排列代码下一个排列分析上一个排列分析第k个排列分析排列序号分析排列序号II分析
[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
desperate633
2018/08/22
1.3K0
排列类算法问题大总结全排列分析带重复元素的全排列代码下一个排列分析上一个排列分析第k个排列分析排列序号分析排列序号II分析
【C++航海王:追寻罗杰的编程之路】STL—next_permutation函数
next_permutation函数会按照字母表顺序生成给定序列的下一个较大的排列,直到整个序列为降序为止。与其相对的还有一个函数——prev_permutation函数。
枫叶丹
2024/06/04
1210
【C++航海王:追寻罗杰的编程之路】STL—next_permutation函数
C++版 - 剑指offer面试题28: 字符串的排列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。
Enjoy233
2019/03/05
6310
自从有了她,再也不怕面试官问我排列问题了
生成一个序列的重排列,是所有可能的字典序中的下一个排列,默认使用 < 运算符实现。
用户9831583
2022/06/16
1800
自从有了她,再也不怕面试官问我排列问题了
全排列(permutation)
显然,对于具有n个元素的集合R,R={r1,r2,r3…rn},其排列方式有n!种。 如:R = {1,2,3},其全排列如下: 1,2,3 1,3,2 2,1,3 2,3,1 3,1,2 3,2,1
lexingsen
2022/02/24
5270
全排列(permutation)
一个易于理解的C++全排列(permutation)实现
通常我们用这两条语句可以得到一个数组的全排列: sort(nums.begin(),nums.end()); //调用next_permutation求全排列的时候必须先给容器排序 do{ get_pirnt(nums) //这里是一个可以打印输出nums的函数 }while(next_permutation(nums.begin(),nums.end()); //调用该C++内置函数可以输出字典序大于当前nums的所有排列。 还可以自己写一个函数实现同样的功能,下面的函数使用递归,每次取出
kalifa_lau
2018/04/26
1.8K0
蓝桥杯之全排列函数next_permutation()运用
在蓝桥杯的题目中大多数都可以运用到全排列函数 充分运用可以节省很多的时间。话不多说来刷题
Max超
2019/01/21
4040
盘点算法竞赛中C++常用的stl库函数
我们都知道,C++中有许多内置的库函数,我们可以直接调用它们,在蓝桥杯,ACM等比赛中,通过使用这些常用的库函数可以大大提高我们的效率,而不用自己去再重新去手写一些函数,那么本篇文章就为大家盘点了一些比较常用的库函数,并附带了例题帮助大家运用理解。
2的n次方
2024/10/15
4940
盘点算法竞赛中C++常用的stl库函数
HDU 6628 (2019杭电第五场 1005) permutation 1 (全排列)
题意:求 n的 全排列 差值序列(后一项减前一项 n-1项) 第 k 小的全排列,2 <=n<=20, 1<= k <=min(10000,n!)
用户2965768
2019/08/14
5500
nyoj------擅长排列的小明
擅长排列的小明 时间限制:1000 ms  |           内存限制:65535 KB 难度:4 描述小明十分聪明,而且十分擅长排列计算。比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想为难他,在这5个数字中选出几个数字让他继续全排列,那么你就错了,他同样的很擅长。现在需要你写一个程序来验证擅长排列的小明到底对不对。 输入第一行输入整数N(1<N<10)表示多少组测试数据, 每组测试数据第一行两个整数 n m (1<n<9,0<m<=n)输出在1-n中选取m个字符进行全排列,按字典
Gxjun
2018/03/21
6550
【算法竞赛】水CF构造题
我太弱了,水水构造tag的题去。 大概只写写思路(毕竟构造题) 打*的是自己想没直接出来的。 发布时间,最早为20220814-14:14,现在为最新水题时间。
Livinfly
2022/10/26
4650
LeetCode 31. 下一个排列(线性扫描)
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
Michael阿明
2020/07/13
3270
每日算法刷题Day16-和为S的两个数字、数字排列、二进制中1的个数
此题可以先sort将数组从小到大排序,然后定义结构vector<vector<int>> res,将结果不断地排下一组和直到返回false为止。
timerring
2022/11/02
2700
每日算法刷题Day16-和为S的两个数字、数字排列、二进制中1的个数
向前字典排序
          next_permutation算法对区间元素进行一次组合排序,使之字典顺序大于原来的排序,有如下两个使用原形,对迭代器区间[first,last)元素序列进行组合排序。当新排序的字典顺序大于原排序时,返回true,否则返回false,利用该算法也可以进行元素排序,但是速度较慢,排序的算法时间复杂度为n!阶乘.          对应的有向后字典排序 prev_permutation算法用于选择一个字典序更小的排序。有如下两个使用原形,对迭代器区间[first,last)元素序列进行组合
Gxjun
2018/03/21
1.3K0
next_permutation(全排列算法)
 STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation。首先我们必须了解什么是“下一个”排列组合,什么是“前一个”排列组合。考虑三个字符所组成的序列{a,b,c}。       这个序列有六个可能的排列组合:abc,acb,bac,bca,cab,cba。这些排列组合根据less-than操作符做字典顺序(lexicographical)的排序。也就是说,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(
Angel_Kitty
2018/04/08
9220
next_permutation(全排列算法)
HDOJ 1716 排列2 next_permutation函数
Problem Description Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。
谙忆
2021/01/20
4110
排列汇总
。即。将每一个组合与一个二进制数相应起来。枚举二进制的同一时候,枚举每一个组合。如字符串:abcde,则有 00000———null 00001———a 00010 ——–b 00011———ab 00100———c … …
全栈程序员站长
2022/07/18
4340
排列组合公式及排列组合算法[通俗易懂]
公式P是指排列,从N个元素取M个进行排列。 公式C是指组合,从N个元素取M个进行组合,不进行排列。 N-元素的总个数 M参与选择的元素个数 !-阶乘,如 9!=9*8*7*6*5*4*3*2*1
全栈程序员站长
2022/07/22
26.3K0
排列组合公式及排列组合算法[通俗易懂]
HDOJ 1716 排列2(next_permutation函数)
例题: Problem B Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 27 Accepted Submission(s) : 10 Problem Description Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。
谙忆
2021/01/20
3840
推荐阅读
相关推荐
全排列 next_permutation的使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验