柯里化与偏函数
偏函数和柯里化的意义
偏函数和柯力化一直有接触到,却不明白有什么作用
在函数式编程中,管道链式调用时会按顺序调用不同的函数,这时候,控制函数参数的数量的意义就体现出来了.
由于pipe中按顺序多次调用不同的函数,但里面的函数都是一元函数(参数只能传一个),并且吐出一个参数,这时候就需要对函数的入参数量进行改造,偏函数&柯里化
function fnA(a){}
function fnB(b1, b2){}
function fnC(c1, c2, c3){}
// 有一个管道函数,传参为函数数组,会串行调用数组内的函数
function pipe(fnArr){}
pipe([fnA, fnB, fnC]); // 调用会有问题,因为三个函数的传参不一致
柯里化
什么是柯里化,wiki里定义如下
在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。
下面写一个柯里化函数
const curry = fn => {
const judge = (...args) =>
args.length === fn.length
? fn(...args)
: (arg) => judge(...args, arg);
return judge;
};
// 测试一下
const fn = curry((a, b, c) => [a, b, c]);
fn("a", "b", "c") // ["a", "b", "c"]
解析下, curry函数接收一个参数为函数, 返回可以curry化操作的新函数
他的核心操作在judge函数里
执行judge('a')('b')('c')
一开始很难理解,让我们人工debugger一下,以fn('a')('b')('c')为例试试
- 第一步执行 judge('a') , args = ['a'], args.length < 3; 返回一个箭头函数
(arg) => judge(['a'], arg)
由于judge函数的接收的形参是(...args), 会把[a],和arg 拼接起来
-
第二步执行 judge(['a'], 'b'), args = ['a', 'b'], args.length < 3 ; 再返回一个箭头函数
(arg) => judge(['a', 'b'], arg) -
第三步 judge(['a', 'b'], 'c'), args = ['a', 'b' 'c'], args.length = 3; 执行fn(...args), 即是执行原函数
fn('a', 'b', 'c'),结束
原则上,柯里化可是将一个多参数的函数转换成多个单参数的函数, 上面的可以执行fn('a')('b','c'), 其中('b','c')是多个参数,这其实是柯里化和偏函数的综合应用.
偏函数
wiki偏函数定义如下
在计算机科学中,局部应用是指固定一个函数的一些参数,然后产生另一个更小元的函数。
这跟柯里化很像拉, 柯里化就是fn(a, b, c)变成 newfn = curry(fn); newfn('a')('b')('c')
而偏函数则是, fn('a','b','c') 变成 newfn = partial(fn, 'a', 'b'); newfn('c')
把一个 n元函数, 转换成一个n-x 元函数
// 偏函数转换函数
function partial(func, ...argsBound) {
return function(...args) {
return func.call(this, ...argsBound, ...args);
};
}
// 测试一下
const fn = partial((arg, ...args) => [arg, ...args], 'b', 'c');
fn('a'); // ['a', 'b', 'c'];
因为这个方法用到了this 指针,就米有用箭头函数喽
偏函数 + 柯里化 混合使用
下面把柯里化和偏函数 混! 合! 在! 一! 起!
const partialCurry = fn => {
const judge = (...args) =>
args.length === fn.length
? fn(...args)
: (arg) => judge(...args, arg);
return judge;
};
const fn = partialCurry((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"]
fn("a")("b", "c") // ["a", "b", "c"]
没错, 即是把 (arg) => judge(...args, arg) 替换为 (...arg) => judge(...args, ...arg) 即可
柯里化过程中,不再要求单一参数,可以是多个参数,算是一个高级柯里化函数吧
小结
至此,我们就可以随心所以地操控函数的参数个数,拿着柯里化和偏函数这两把宝剑勇闯函数式编程的世界吧!呀~~~哈~~~!