在
这个知乎问题的回答中,
wsivoky 写了几个基本的函数:
用 javascript (你也可以把它当作函数式语言)就是这样:
function one (a) { return function (b) { return a(b); } }
.....
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))