函数式编程学习
1.函数式编程
https://zhuanlan.zhihu.com/p/21714695
1.1 纯函数(没有副作用的函数)
副作用的概念:一个带有副作用的函数不仅只是简单的返回一个值,还干了一些其他的事情,比如:
修改一个变量
- 直接修改数据结构
- 设置一个对象的成员
- 抛出一个异常或以一个错误终止
- 打印到终端或读取用户的输入
- 读取或写入一个文件
- 在屏幕上绘画 如果你还记得一些初中的数学知识的话,函数 f 的概念就是,对于输入 x 产生一个输出 y =
f(x)。这便是一种最简单的纯函数。纯函数的定义是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。
下面来举个栗子,比如在Javascript中对于数组的操作,有些是纯的,有些就不是纯的:
var arr = [1,2,3,4,5];
// Array.slice是纯函数,因为它没有副作用,对于固定的输入,输出总是固定的
// 可以,这很函数式
xs.slice(0,3);
//=> [1,2,3]
xs.slice(0,3);
//=> [1,2,3]
// Array.splice是不纯的,它有副作用,对于固定的输入,输出不是固定的
// 这不函数式
xs.splice(0,3);
//=> [1,2,3]
xs.splice(0,3);
//=> [4,5]
xs.splice(0,3);
//=> []
在函数式编程中,我们想要的是 slice 这样的纯函数,而不是 splice这种每次调用后都会把数据弄得一团乱的函数。
1.2 函数柯里化(多参数函数转换成单参数函数)
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。 例如:
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
1.3 函数组合(compose和pipe)
webpack loader加载顺序是从右到左,其实就是因为选择了compose(compose中是采用reduceRight)方式
var arr = [1, 2, 3, 4];
// 从左往右,第二个参数是设置第一次遍历对初始值
arr.reduce(function(total, val, index, arr){
console.log('total', total);
return total + val;
}, 100);
var add = x => x + 2;
var double = x => x * x;
var mul3 = x => x * 3;
function pipe(...fns){
return x => fns.reduce((f, v) => {
return v(f);
},x);
}
const rfn = pipe(add, double, mul3);
console.log(rfn(2)); // 输出48,mul3(double(add(2)))
如果换成reduceRight就是从右往左执行了,add(double(mul3(2))),这个就是webpack从右到左顺序执行的原理。
compose和pipe
compose(f,g,h)返回的函数完成类似(…args) => f(g(h(…args)))的功能。即从右到左组合多个函数,前面函数的返回值作为下一个函数的参数; (reduceRight)
pipe(f,g,h)返回的函数完成类似(…args) => h(g(f(…args)))的功能,即从左到右组合多个函数,前面函数的返回值作为下一个函数的参数;(reduce)
1.4 函子
般约定,函子的标志就是容器具有map方法。该方法将容器里面的每一个值,映射到另一个容器。学习函数式编程,实际上就是学习函子的各种运算。