函数式编程:柯里化的变型应用

函数柯里化不仅极大地提高了代码的可复用性与灵活性,而且降低了代码的耦合性,但是在生产环境中使用时发现了美中不足的一点,遂有此文,目的是改造柯里化函数结构,使之更方便使用、易于理解。

为方便理解,本篇文章虚拟了一个简单的业务场景:更新指定栏目下指定节目的描述信息

普通的函数柯里化

首先,在变型前,一起看看大部分函数柯里化的实现与使用:

1
2
3
4
5
6
7
8
9
let updateProgramDesc = colunmID => {
return programID => {
desc => {
// do something...
}
}
}
// 使用方法,更新 ID为10的栏目 下 ID为1000的节目 的描述信息为’description content.‘
updateProgramDesc(10)(1000)('description content.');

变型初衷

使用时很明显,每一层的函数在传参的时候很容易让人产生困惑:

  • 所使用的柯里化后的函数参数传到的哪一个层级?
  • 该传入哪个参数了?
  • 传入的这个参数是干什么的?

尤其在柯里化程度较高的情况下这种困扰尤为明显,使用时经常需要仔细观察上下文,甚至是去查看原函数来确定传参:

1
func(param1)(param2)(param3)(param4)(param5)(param6);

柯里化的变型

出于以上初衷,对柯里化函数的结构做了一些调整,如下:

1
2
3
4
5
6
7
8
9
10
11
let updateColumn = colunmID => {
return {
program(programID) {
return {
desc(desc) {
// do something...
}
}
}
}
}

发现哪里不同了吗?

下面是变型后的使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Fully chain calls.
updateColunm(10).program(1000).desc('description content.');

// Partial application invoke.
let column = updateColunm(10);
column
.program(1001)
.desc('update the description of program 1001 in column 100.');
column
.program(1002)
.desc('update the description of program 1002 in column 100.');

let program = column.program(1003);
program.desc('update the description of program 1003 in column 100.');
program.desc('update the new description of program 1003 in column 100.');

优点 & 不足

优点

通过return object代替function的方式,对象名可以非常恰当地对当前传参进行描述,使用时更清晰易懂,不易造成使用时确定传参困难、传参错误等情况。

其实实现思想很简单吧~

不足

不过这种方法也有一个不足之处就是会增加少量代码与缩进,不过可以尝试使用Promise来实现,会更优雅自然~

进一步可能

updateDesc(desc).ofProgram(programID).inColumn(columnID);

发现了吗?可以写出更贴近自然语言的柯里化函数!
不过前文没有这么做,你知道是为什么吗?

灵感来源

jQuery的链式函数调用~

参考文档:

A Beginner’s Guide to Currying in Functional JavaScript
Higher-Order Functions in JavaScript
JavaScript函数柯里化的一些思考

所有文章非特别说明皆为原创。技术更迭迅猛,部分内容可能会作修改,为保证信息与源同步,转载时请务必注明文章出处!谢谢合作 :-)