马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

Currying 及应用

[复制链接]
查看1830 | 回复1 | 2019-10-12 10:22:34 | 显示全部楼层 |阅读模式

Currying,中文多翻译为柯里化,感觉这个音译还没有到达类似 Humor 之于幽默的传神地步,反面直接利用 Currying。

什么是 Currying

Currying 是这么一种机制,它将一个接收多个参数的函数,拆分成多个接收单个参数的函数。

观察下面的代码:

  1. function add (a, b) {
  2. return a + b;
  3. }
  4. add(3, 4); // returns 7
复制代码

add 接收两个参数 ab,并返回它们的和 a+b

颠末 curry 化处理处罚后,函数成了如下情势:

  1. function add (a) {
  2. return function (b) {
  3. return a + b;
  4. }
  5. }
复制代码

如今 add 接收一个参数 a,返回另一个接收一个参数 b 的函数。

  1. add(3)(4);
  2. var add3 = add(3);
  3. add3(4);
复制代码

如今当调用 add(3) 后,得到的不是和,而是另一个接收一个参数的函数,因此,add 的返回可以继承被调用,add(3)(4) 反面的这次调用才会将 4 加到 3 上得到和。

var add3 = add(3) 如许的单次调用,得到的函数结果相当于是将 3 保存在了新函数的闭包中,该函数会对传入的参数加 3。

留意这里提到了将入参 3 保存 到了闭包中后续利用,很轻易联想到 Function.prototype.bind(),它就可以对传入的函数提前绑定一些预设的入参:

  1. function.bind(thisArg[, arg1[, arg2[, ...]]])
复制代码

反面会看到,正由于 bind 和 Currying 有点关系,在实现任意函数的 Currying 化时会用到它。

留意到 Currying 化的界说,实在是将多个参数打散到多个函数中,这个过程可通过代码来主动化,以到达将任意多入参函数举行 Currying 化的目标,反面讨论实现。

偏函数/Partial Application

区别与 Currying,如果在拆分入参的过程中,这些拆分出来的函数不是一次只应用其中的一个,而是任意多个,则这些函数就是部分应用(Parital application)了原函数中的入参,称作偏函数。

观察下面的 add 函数,实在是将前面示例中的 add 入参举行了扩充,由两个增长到四个:

  1. function add(a, b, c, d) {
  2. return a + b + c + d;
  3. }
复制代码

那么如下的函数就都是偏函数,它们都部分应用了 add 的入参:

  1. function partial1(a) {
  2. return function(c) {
  3. return a + b + c + d;
  4. };
  5. }
  6. function partial2(a, b) {
  7. return function(c, d) {
  8. return a + b + c + d;
  9. };
  10. }
  11. function partial3(a, b, c) {
  12. return function(d) {
  13. return a + b + c + d;
  14. };
  15. }
复制代码

偏函数中这种入参的拆分和部分应用,并不但限于一层的拆分,可以是任意多次的:

  1. function partial1(a, b) {
  2. return function partial2(c) {
  3. return function partial3(d) {
  4. return a + b + c + d;
  5. };
  6. };
  7. }
  8. partial1(1)(2, 3)(4); // 10
复制代码

其中,partial1partial2partial3 一起构成了原 add 函数的偏函数。

可以看到,偏函数是 Curring 更加一样平常(general)的情势,下面看如何实现将任意函数举行 Currying 化,或偏函数化。

将一样平常化函数举行 Currying 化

我们必要构造这么一个函数假设名叫 curry

  1. function curry(fn){
  2. // 待实现
  3. }
复制代码

调用 curry 后,我们可以得到原函数 Curry 化后的版本,

  1. function add (a, b) {
  2. return a + b;
  3. }
  4. var currified = curry(add);
复制代码

即上述 currified 应该等效为:

  1. function currified (a) {
  2. return function (b) {
  3. return a + b;
  4. }
  5. }
复制代码

起首,通过 Function.length 是可以知道一个给定函数其预期的入参个数的。

再加上前面提到的 bind 函数,可以得到如下的实现:

  1. function curry(f) {
  2. return function currify() {
  3. const args = Array.prototype.slice.call(arguments);
  4. return args.length >= f.length ?
  5. f.apply(null, args) :
  6. currify.bind(null, ...args)
  7. }
  8. }
复制代码

下面测试一下:

  1. function add(a, b) {
  2. return a + b;
  3. }
  4. var currified = curry(add);
  5. currified(1)(2); // 3
复制代码

而且以上实现不但是简朴的 Currying 化,可以是任意数目和任意次数的 parial application:

  1. function add(a, b, c, d) {
  2. return a + b + c + d;
  3. }
  4. var currified = curry(add);
  5. currified(1)(2)(3)(4); // 10
  6. currified(1)(2, 3)(4); // 10
  7. currified(1, 2)(3, 4); // 10
复制代码

总之就是各种外形hàn姿势,各种颜色hàn皮肤的组合。

主动化的 CurryIng 倒是实现了,可说了半天,它详细有什么实用价值。

函数的组合(function composition)

我们知道代数里面可以有函数的组合,譬如:

  1. <code>f(x) = x * x
  2. g(y) = y + 1
  3. g(f(x)) = x * x + 1
  4. g(f(2)) = 2 * 2 + 1 = 5
  5. </code>
复制代码

上述代数表达转成 JavaScript 即:

  1. function f(x) {
  2. return x ** 2;
  3. }
  4. function g(y) {
  5. return y + 1;
  6. }
  7. g(f(2)) // 5
复制代码

这里用到了两个函数 fg 团结起来得到一个结果,他们都分别只接收一个入参同时返回一个结果。

像如许只接收一个入参并返回一个结果的函数,便符合组装的需求,可像上面如许自由组合。通过上面的讨论我们知道,任意函数都可颠末 Currying 化处理处罚后变成多个只接收单个入参的函数。这就为函数的组合提供了底子。

因此我们可以将 fg 的结合形成一个新的函数,这个函数作为对外的接口被调用即可。

  1. const compose = fn1 => fn2 => input => fn1(fn2(input));
复制代码

利用:

  1. const myFn = compose(f)(g);
  2. myFn(2); // 5
复制代码

像上面的 compose 还不敷一样平常化,他只接收两个函数并对其举行结合,下面来看更加一样平常化的函数组合,将实现接收任意多个函数。

  1. const pipe = (...fns) => input => fns.reduce((mem, fn) => fn(mem), input)
  2. const double = x => x * 2
  3. const addOne = x => x + 1
  4. const square = x => x * x
  5. pipe(square, double, addOne)(2)
复制代码

上面的 pipe 将对输入依次应用 入参中的各函数,以是取名 pipe 管道流。

以上,函数的组装。

相关资源

  • What is 'Currying'?
  • Curry and Function Composition
  • An elegant and simple curry(f) implementation in Javascript
  • lodash - curry
  • Function.length
  • Wikipedia - Currying
  • MDN - Function.prototype.bind()
  • Currying versus partial application (with JavaScript code)
  • Currying is not idiomatic in JavaScript
  • Functional JS #6: Function composition
  • Functional JavaScript: Function Composition For Every Day Use






来源:https://www.cnblogs.com/Wayou/p/currying_and_function_compose.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则