FunctionalProgramming函数式编程

纯函数 pure function
  1. 引用透明(Referential transparency),对于同样的传入参数永远返回同样的输出值,意味着不能依赖可变状态
  2. 无副作用(side-effect free),副作用可以是I/O操作,修改可变对象,重新赋值对象等等。
Advantages of functional programming
  1. 易于编写和调试,因为不依赖可变状态
  2. 返回值可以被缓存或memoized,来避免重复计算
  3. 易于测试,因为没有依赖,不用像logging,ajax,database之类需要模拟数据测试
  4. 把数据从逻辑中分离
higher-order functions : 要么把函数当做参数,要么返回一个函数的函数

利用Object.freeze阻止对象值修改
没有返回值的函数往往是空函数或者是有副作用的函数

// identity 同一律
map(id) === id;

// composition 组合律
compose(map(f), map(g)) === map(compose(f, g));

柯里化 Currying

currying is the process of taking a function that accepts n arguments and turning it into n functions that each accepts a single argument.
在计算机科学中,柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

不可变数据结构
惰性求值
函数组合
尾递归优化

向量

向量是带有索引的一组数据,是不可变数据结构immutable,是持久性数据结构persistent
持久性是指数据结构在被操作的时候永远保持着前一版本
不可变性是指在被创建之后再也不能改变
所以持久性约束的是操作,不可变性约束的是数据

线程不安全是指一个值会被多个线程中的操作同时修改,带来的问题是你很难预测以及重现这值在某个时间到底是什么,解决线程安全通常会用到互斥锁,原子操作等,这些方式大大的增加了编程和测试的难度。
不可变性保证了不管是主线程代码还是回调函数,拿到的值都能一直保持不变,所以不再需要关心会出现线程安全问题。

mori
方括号代表向量
圆括号代表惰性序列(Lazy Sequence)

threshold

在不可变的前提下,如果真的需要循环,那么只能使用递归

柯里悖论的求解?

非尾递归例子:

function fact(n) {
    if(n==0) return 1;
    return n * fact(n-1);
}

尾递归例子:

function fact(n, acc=1) {
    if(n==0) return acc;
    return fact(n-1, acc * n);
}

尾递归优化成循环:

function fact(n) {
    let acc=1, i=n;
    while(i!=0) {
        acc = acc * i;
        i--;
    }
    return acc;
}

普通递归可以优化成尾递归再优化成循环

相互递归 Mutual Recursion
有穷状态机 DFA

Trampoline 是一个函数:

  1. 接收一个函数,一个或多个该函数的参数
  2. 调用该函数
  3. 如果返回值是个函数,调用返回的函数
  4. 如果返回值不是个函数,停止,返回

相互递归最终的优化依然靠循环

mori.trampoline(eat_money, input_seq)  
function eat_money() {
    if(input_seq.length == 0) return;
    let input = input_seq.shift();
    if(input == "five") {
        return function() {return choose(input_seq)}
    } else {
        return function() {return eat_money(input_seq)}
    }
}

// trampoline实现的大致过程
let res = eat_money(input_seq);
while(true) {
    if(typeof res == "function") res = res();
    else break;
}  

自由变量 Free 与 约束变量 Bound , 自由变量指的是函数中既不是参数,也不是局部变量的那个变量,约束变量就是参数或局部变量

函数(约束1)(约束2)(约束3)... => 值

mori.reduce(fn,0,[1,2,3]);
mori.reduce(mori.sum,0,mori.map(mori.inc, [1,2,3])); // 9

Reducer

  1. 接收一个xf函数和一个collection
  2. 用xf转换reducing函数,并应用到collection

Transducer就是那个xf

Reducer的出现只是因为想保持原始reduce的API不变,而Transducer的引入则是提供了另外一种reduce API:
transduce(transducer, reducing, initValue, collection);

REPL Read-Eval-Print-Loop
core.async
goroutine

Sweet.js
clojure

参考库:

  1. Ramda