函数式编程(fp)的数学推导

这个知乎问题的回答中, wsivoky 写了几个基本的函数:

用 javascript (你也可以把它当作函数式语言)就是这样:

function one (a) {
return function (b) {
return a(b);
}
}
.....
用 javascript 就是这样:
function succ (a) {
  return function (b) {
    return function(c) {
      return b( a(b)(c) );
   }
 }
}
以及two的定义:
function two(a) {
return function (b) {
return succ(one)(a)(b);
}
}这里面的推导感觉就像数学公式的推导。我自己整理了一下思路,算是做个笔记吧。
用第二个字代表下标,以区分不同函数(或者说公式)中的变量,一次(这里刚好调用每次一个参数)函数调用fn()代表封装返回一次函数(return in function),函数本身定义就已经有了一次封装,内部如果再定义一个函数就再加一次参数,这里假定所有函数都需要参数,所以one函数接受的参数函数自己也有参数:
one(a1) = a1(b1) , 对外两次参数(包两层),实际调用格式要写成return one(a)(b)
succ(as) = bs(as(bs)(cs)), 对外三次参数(包三层), 下面这行就是它的调用格式return succ(a)(b)(c)
two(a2)=succ(one)(a2)(b2), 对外两次参数(包两层),格式return two(a)(b),one不是需要传递进来的参数,不是封装的结果

下面来解析上面最后一行的two公式(或者说two函数)如下,把公式解析到最底层的abc基本函数的调用,把succ和one解析掉:
two=succ(one)中把one公式应用(代入)到succ公式的as里,即消掉了参数as函数,同时也去掉as变量的引用,as既是函数,也是变量。
succ(one)变身 = bs(<a1(b1)>(bs)(cs)) 尖括号表示仅替代了函数变量as,参数还需要再替换
这时因为参数bs是给来替换的One函数的参数,也就是One函数的第一次参数,可以替换a1, 替换后=bs(<bs(b1)>(cs)), 
这时参数cs是给One公式代入后运行得到的函数再运行需要的那个参数,即One公式的第二次参数,所以可以用来代替b1的,所以
two可以写成two = succ(one) = bs(bs(cs)),这个新公式作为two的函数体解析后的写法,和上面老的two公式是等价的。这个新的两次参数也和老two公式的两次参数(不是两个参数,是两次)匹配
所以two把第一次参数a2代入后替换掉bs变量,
two=a2(a2(cs)),
再把第二次的参数b2代入cs,得到two = a2(a2(b2)),不加下标的通用写法就是two=a(a(b)),为了解析还是保留下标的好。

依次类推,如果说three = succ(two),函数体省略,两个参数:第一个是函数参数,第二个是给前一个用的参数, 那么还是同理把two公式代入到succ(as)公式,得到
three=succ(two) = bs(<a2(a2(b2))>(bs)(cs)), 再替换参数得到 three = bs(bs(bs(cs))),重新编组参数得到的通用写法就是
three = a(a(a(b))
加下标区分,应该写成three = a3(a3(a3(b3))

发表回复