一、范畴轮
函数式编程是范畴论的数学分支,是一门很复杂的数学,认为世界上所有概念体系都可以抽象出一个个范畴。- 彼此之间存在某种关系概念、事物、对象等等,都构成范畴。任何事物只要找出他们之间的关系,就能定义 。
- 箭头表示范畴成员之间的关系,正式的名称叫做“态射”(morphism)。范畴论认为,同一个范畴的所有成员,就是不同状态的“变形”(transformation)。通过“态射”,一个成员可以变形成另一个成员。

二、函数式编程基本理论
函数式编程其实相对于计算机的历史而言是一个非常古老的概念,甚至早于第一台计算机的诞生。函数式编程的基础模型来源于 λ (Lambda x=>x*2)演算,而λ 演算并非设计于在计算机上执行,它是在 20 世纪三十年代引入的一套用于研究函数定义、函数应用和递归的形式系统。- 函数式编程不是用函数来编程,也不是传统的面向过程编程。主旨在于将复杂的函数符合成简单的函数,运算过程尽量
写成一系列嵌套的函数调用。 - JavaScript 是披着 C 外衣的 Lisp。
Common Lisp的写法如下:
(defun foo (n)
(lambda (i) (incf n i)))
为啥说 JavaScript 是披着 C 外衣的 Lisp
function foo (n) {
return function (i) {
return n += i } }
可怜的 Java(8之前)只能给一个近似的解(还只支持整数)
public interface Inttoint {
public int call (int i);
}
public static Inttoint foo (final int n) {
return new Inttoint () {
int s = n;
public int call (int i) {
s = s + i;
return s;
}
};
}
三、专业术语
纯函数
对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。
var xs = [1,2,3,4,5];
// Array.slice是纯函数,因为它没有副作用,对于固定的输入,输出总是固定的
xs.slice(0,3);
xs.slice(0,3); // 没改
xs.splice(0,3);
xs.splice(0,3); // 改了
纯函数不仅可以有效降低系统的复杂度,还有很多很棒的特性,比如可缓存性。
比如:
import _ from 'lodash';
var sin = _.memorize(x =>
Math.sin(x));
//第一次计算的时候会稍慢一点
var a = sin(1);
//第二次有了缓存,速度极快
var b = sin(1);
不纯的话:
//不纯的
var min = 18;
var checkage = age => age > min;
//纯的,这很函数式
var checkage = age => age > 18;
不纯的版本中,checkage 不仅取决于 age 还有外部依赖的变量 min。纯的版本中 checkage 把关键数字 18 硬编码在函数内部,扩展性比较差。
那么,我们怎么解决这个问题呢?
柯里化
我们可以把 min 也从外部传入
function fun(min) {
return function (age) {
return min > age;
}
}
fun(10)(18);
简写为
const fun = min => age => age > min;
事实上柯里化是一种“预加载”函数的方法,通过传递较少的参数,得到一个已经记住了这些参数的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法。
在写纯函数的过程中,我们很容易写出柯里化的洋葱代码
h(g(f(x))),为了解决函数嵌套的问题,我们需要用到函数组合
函数组合以及 Point Free 风格
Point Free 风格把一些对象自带的方法转化成纯函数,不要命名转瞬即逝的中间变量。
const fun = str => str.toUpperCase().split(" ");
fun("hello world!"); // [ 'HELLO', 'WORLD!' ]
在这个函数中,我们使用了 str 作为我们的中间变量,但这个中间变量除了让代码变得长了一点以外是毫无意义的。
我们改为柯里化:
const split = str => word => word.split(str);
const upper = word => word.toUpperCase();
const res=split(" ")(upper("hello world!"));
避免出现洋葱代码,我们可以改为Point Free风格
const compose = (f, g) => x => f(g(x));
const split = str => word => word.split(str);
const upper = word => word.toUpperCase();
const fun = compose(split(" "), upper);
const res = fun("hello world!");
console.log(res);