λ演算 (Lambda Calculus) 二 : 柯里化和编码

1. 柯里化(Currying)

柯里化就是把一个多参数的函数转化为单参数函数的方法。类似于复合函数。

现在我们有两个输入值xy对应一个函数f (x , y),怎么让函数F一开始只接受一个值呢?

我们可以先定义一个 F1 = λx.F2, 然后令 F2 = λy.f (x , y) 完成柯里化。

2. 编码(Encoding)

有了这么多运算法则具体能有什么用呢?接下来我们就可以用一些编码来表示编程语言里的基本数据和语句,实现函数式编程。

TRUE := λxy.x

FALSE := λxy.y

NOT := λfxy.fyx

OR := λxy.xxy

AND := λxy.xyx

IFELSE := λfxy.fxy

我们都知道在计算机的二进制世界里0就是NOT,1就是TRUE。在λ演算中同样如此:

ZERO := λxy.y

并且我们有一个加数器,以零为基础每次加一可以得到所有自然数,相对的我们还有减数器每次减一。

SUCCESSOR := λxyz.y(xyz)

PRED := λnfx.n(λgh.h(gf)) (λy.x) (λu.u)

以此我们可以得到一个自然数的通项公式:

n = λfx. f^n (x)

我们还有一些其他的运算法则:

ADD := λxypq.xp(ypq)

MULT := λxyz.x(yz)

EXP := λxy.yx

我们来试试!

 NOT TRUE

= (λfxy.fyx) (λxy.x) 
= (λfxy.fyx) (λab.a)
= λxy.(λab.a) yx
= λxy.(λb.y) x
= λxy.y
= FALSE
   ONE
= SUCCESSOR ZERO
= (λxyz.y(xyz)) (λxy.y)
= (λxyz.y(xyz)) (λab.b)
= λyz.y((λab.b) yz) 
= λyz.y((λb.b) z) 
= λyz.yz
= ONE
    ADD ZERO ONE
= (λxypq.xp(ypq)) (λxy.y) (λxy.xy)
= (λxypq.xp(ypq)) (λab.b) (λcd.cd))
= (λypq. (λab.b) p(ypq)) (λcd.cd))
= (λypq. (λb.b) (ypq)) (λcd.cd))
= (λypq. (ypq)) (λcd.cd))
= (λpq. ((λcd.cd)pq)) 
= (λpq. ((λd.pd)q)) 
= (λpq.pq)) 
= (λxy.xy)
= ONE

这样我们就可以完成基本的运算,我们知道现代过程式编程语言有两种基本结构,分别是判断语句和循环语句,我们已经给出了IFELSE的编码实现判断语句。那么循环语句呢?很遗憾,在函数式编程里一般没有循环语句,因为在函数式编程里只有函数,我们要实现循环只能利用递归(Recursion) —— 也是我们经常见到的求斐波那契数列的方法。下一章我们介绍λ演算中列表的编码实现和函数式编程中的递归,用递归来构造和遍历列表。

猜你喜欢

转载自www.cnblogs.com/qianyexi/p/12159374.html