定义
curry**
translating
the evaluation of a function that takes multiple args(多参函数)
into
evaluation a sequence of functions,each with a single arg(一系列单参函数).
即:f(x, y, z) => f(x)(y)(z)
被 curry 化的函数,一般地,参数凑齐了,就会执行,如 loadsh 就是这样处理的。但并没有规范的做法,所以也可以是 f(x, y, z) => f(x, y)(z) 或者 f(x)(y)(z)() 或者 f(x)(y)(z).run() 等等。
It provides a way of automatically managing how arguments are passed to functions and expression.
一些语言中,几乎总是使用 curry 实现多参函数,如 ML/Haskell。在这些语言中,函数只能有一个参数(规范做法)。
currying 与 partial application 有点类似,但不一样。
只接收一个参数的成为一元函数,接收两个参数称为两元参数,接收多个参数的称为多元函数。接收不确定参数的称为变参函数。柯里化是把一个多参数函数转换成一个嵌套的一元函数的过程。
通用 curry 函数
参数够了就执行:
const curry = (fn) => {return function curryFunc(...arg) {if (arg.length < fn.length) {return function () {return curryFunc.apply(null, [...arg, ...arguments]);};}return fn.apply(null, arg);}};const func = (a, b) => console.log(a - b);curry(func)(1)(2)
专用 curry 函数
对使用场景有要求,不具备通用性:
function add(x, y){ return x + y }function sub(x, y){ return x - y; }function mul(x, y){ return x * y;}function curry(f, x){return function(y){return f(x, y);}}curry(add, 3)(4); // 7curry(sub, 8)(6); // 2curry(mul, 5)(6); // 30
参数为0个时触发调用
const coreAdd = (...rest) => {const args = restreturn args.reduce((acc, element) => ( acc += element ), 0)}function addCurry() {const args = Array.prototype.slice.call(arguments)return function() {const newArgs = Array.prototype.slice.call(arguments)const totalArgs = newArgs.concat(args)if(newArgs.length === 0) return coreAdd(...totalArgs)return addCurry(...totalArgs)}}const addValue = addCurry(2, 3)(1)(8, 5)()alert(addValue) // 19
https://medium.com/@anilchaudhary453/method-chaining-currying-javascript-b6fc3324592c
触发条件是显式 .result()
function add (num) {function adder (n) {if(n !== undefined) {num += nreturn adder} else {return num}}adder.result = function() {return num}return adder}add(1)(2)(3)(4)(5).result() // 15add(1)(2)(3).result() // 6add(1).result() // 1
lodash 中的 curry
lodash 中的 curry 支持 placeholder,以便于调整参数的提供次序。
var abc = function(a, b, c) {return [a, b, c];};var curried = _.curry(abc);curried(1)(2)(3);// => [1, 2, 3]curried(1, 2)(3);// => [1, 2, 3]curried(1, 2, 3);// => [1, 2, 3]// Curried with placeholders.curried(1)(_, 3)(2);// => [1, 2, 3]
参考:https://lodash.com/docs/#curry
偏应用
允许开发者部分地应用函数,即将给定函数的部分参数固化,然后返回一个函数,该函数仅接收未固化的参数。
通用 partial 函数
Function.prototype.partial = function(...args){for (let i = args.length; i < this.length; i++){args.push(undefined) // 补齐,跟fn的参数列表对应上}return (...remainArgs) => {let realArgs = []let j = 0;args.forEach((arg, i) => {if(arg === undefined){realArgs.push(remainArgs[j++])} else {realArgs.push(arg)}})return this(...realArgs)}}
使用示例 1
let timer3s = setTimeout.partial(undefined, 3000)timer3s(() => console.log('hello')) // 3s后输出hellotimer3s(() => console.log('hello2')) // 3s后输出hello2timer3s(() => console.log('hello3')) // 3s后输出hello3
使用示例 2
function add4(a,b,c,d) { return a + b + c + d }var _add4 = add4.partial(1,undefined,3,undefined);_add4(2,4) // 10_add4(3,5) // 12
参考:
https://simple.wikipedia.org/wiki/Currying
https://en.wikipedia.org/wiki/Currying
https://javascript.info/currying-partials
https://blog.benestudio.co/currying-in-javascript-es6-540d2ad09400
https://blog.bitsrc.io/understanding-currying-in-javascript-ceb2188c339
https://codeburst.io/currying-in-javascript-ba51eb9778dc
https://github.com/lodash/lodash/blob/npm/_createCurry.js
