函数式编程(三)

前面两节介绍了纯函数和高阶函数,在函数式编程中,函数就是咱们的砖块。咱们编写一些能够完成很是具体任务的函数,而后像乐高积木同样将他们搭建起来。编程

这就是所谓的函数组合。数组

函数组合

先看两个纯函数缓存

let add10 = value => value + 10;
let mult5 = value => value * 5;

let mult5AfterAdd10 = value => mult5(add10(value))

这样写代码很容易写出h(g(f(e(x)))),这样层层相套的代码,一层一层拨开它的心。
为了解函数嵌套的问题,咱们能够先预约义一个组合函数app

var compose = function(f,g) {
  return function(x) {
    return f(g(x));
  };
};

而后改写上面的例子函数式编程

let mult5AfterAdd10 = compose(mult5, add10)
mult5AfterAdd10(5)

这样作的可读性远远高于嵌套一大堆的函数调用。函数

Point Free

把一些对象自带的方法转化为纯函数,不要命名转瞬即逝的中间变量this

网上有不少关于Point Free的案例,我认为都不怎么能说明问题,下面这个例子是我精心准备的机密,通常不外传。prototype

const f = str => str.toUpperCase().split('');
const toUpperCase = word => word.toUpperCase();
const split = x => (str => str.split(x));


const f = compose(split(''), toUpperCase)

f("aa vv")
//咱们没有使用到str变量

咱们不须要指定冗余的参数。因为没必要指定参数,因此也就没必要考虑为它们命名。其次,因为更简短使得更容易阅读。Pointfree 的本质就是使用一些通用的函数,组合出各类复杂运算。上层运算不要直接操做数据,而是经过底层函数去处理。这就要求,将一些经常使用的操做封装成函数。因此说这种方式慎用。code

看到这里你是否是觉得本身就了解函数式编程了呢?nonono?下面我有个问题想考考你。对象

let add = (value, y) => value + y;
let mult5 = value => value * 5;

我想改写上面的mult5AfterAdd10函数,把它转成更通用的mult5AfterAdd,你想到用上面学到的姿式,

let mult5AfterAdd = compose(mult5, add)

显然这个不行的,由于add函数须要接收两个参数,实际只传递了一个参数,因此它会将一个错误的结果传递给mult5。这最终会产生一个错误的结果。
咱们怎么解决这个问题?事实证实有一种方法,它就是柯里化(Currying)

下面咱们来看看函数的柯里化。
有这样一道题目,实现一个函数,实现以下功能:

var result = sum(1)(2)(3);
console.log(result);//6

如下是一种实现方式

function add(a){
    var sum = 0;
        sum += a;
    return b => {
        sum += b;
        return c => {
            sum += c;
            return sum;
        }
    }
}
add(1)(2)(3);//6

咱们来解决上面遗留的问题,经过改写add函数

let add = x => y => x + y
let compose = (f, g) => x => f(g(x));
let mult5AfterAdd10 = compose(mult5, add(10));

咱们就是将简单常见的add函数转化成了柯里化函数,这样add函数就变得更加自由灵活了。咱们先将第1个参数10输入,而当mult5AfterAdd10函数被调用的时候,最后1个参数才有了肯定的值。

柯里化

柯里化一般也称部分求值,其含义是给函数分步传递参数,每次传递参数后,部分应用参数,并返回一个更具体的函数接受剩下的参数,中间可嵌套多层这样的接受部分参数函数,逐步缩小函数的适用范围,逐步求解,直至返回最后结果。

一个简单的通用模块的函数柯里化封装

const curry = fn => {
    const _args = [];
    return function cb() {

        if(arguments.length === 0) {
            return fn.apply(this, _args);
        }

        Array.prototype.push.apply(_args, [...arguments]);

        return cb;
    }
}

函数柯里化是一种预加载函数的方法,经过传递较少的参数,获得一个已经记住了这些参数的新函数,某种意义上来说,这是一种对参数的“缓存”,是一种很是高效的编写函数的方法。⚠️参数顺序是可否最大程度利用柯里化的关键所在。

相关文章
相关标签/搜索