Lambda演算
一个前人写的有关Lambda演算的项目,里面包含了一个完整的关于Lambda演算的起源和讲解的pdf文件,还有能在不同平台下运行的解释器。
Lambda演算是一套用于研究函数定义、函数应用和递归的形式系统。它由 Alonzo Church 和 Stephen Cole Kleene 在 20 世纪三十年代引入,Church 运用 lambda 演算在 1936 年给出 判定性问题 (Entscheidungsproblem) 的一个否定的答案。这种演算可以用来清晰地定义什么是一个可计算函数。关于两个 lambda 演算表达式是否等价的命题无法通过一个通用的算法来解决,这是不可判定性能够证明的头一个问题,甚至还在停机问题之先。
这篇文章写于软工与计算一刚刚上完Lambda演算之后,因为理论和应用之间存在很大的距离,很多人觉得Lambda演算没有什么作用,这篇文章注在以更简单直白的语言为大家讲解Lambda演算并且告诉大家这个东西究竟有什么用。
首先先讲一讲Lambda演算里面得几个定义和几个操作:
定义
定义1. 𝜆 项
假设我们有一个无穷的字符串集合,里面的元素被称为变量(和程序语言中变量概念
不同,这里就是指字符串本身)。那么 𝜆 项定义如下:
- 所有的变量都是 𝜆 项(名为原子)
- 若 𝑀 和 𝑁 是 𝜆 项,那么 (𝑀 𝑁 ) 也是 𝜆 项(名为应用)
- 若 𝑀 是 𝜆 项而 𝜙 是一个变量,那么 (𝜆𝜙.𝑀) 也是 𝜆项(名为抽象)。
解释
1.函数包括因变量和自变量,自变量作为变量可以看成 𝜆 项,因变量本质上也是一个变量(废话),所以因变量也是变量,可以简单的认为几乎所有的东西都是 𝜆 项
2.简单来说,就是可以将括号内部的东西看成一个整体。
3.即一种函数的表达方式,𝜆表示这是一个函数,𝜙是函数里的一个变量,𝑀是表达式
(下面为了方便起见,所有的𝜆都用\代替,这也是解释器中的写法)
这些都是𝜆项
(𝜆𝑥.(𝑥 𝑦))
(𝑥(𝜆𝑥.(𝜆𝑥.𝑥)))
((((𝑎 𝑏) 𝑐) 𝑑) 𝑒)
(((𝜆𝑥.(𝜆𝑦.(𝑦 𝑥))) 𝑎) 𝑏)
((𝜆𝑦.𝑦) (𝜆𝑥.(𝑥 𝑦)))
(𝜆𝑥.(𝑦 𝑧))
在lambda演算里面,括号是非常重要的(在一般的数学里也很重要),它涉及到了运算的顺序和后面β规约的时候能不能正确规约
下面介绍三个括号省略的规则:
1.最外层的括号可以省略,(\x.x)可以写成\x.x
2.左结合的应用型的lambda项,如(((MN)P)Q),括号可以省略,表示为M N P Q(这个规则十分重要)
3.抽象型的lambda项,(𝜆𝜙.𝑀)的M里最外层的括号可以省略,如\x.(xy)可以写成\x.xy
省略表示
𝜆𝑥.𝜆𝑦.𝑦 𝑥 𝑎 𝑏
(𝜆𝑥.𝜆𝑦.𝑦 𝑥) 𝑎 𝑏
𝜆𝑔.(𝜆𝑥.𝑔 (𝑥 𝑥)) 𝜆𝑥.𝑔 (𝑥 𝑥)
𝜆𝑥.𝜆𝑦.𝑎 𝑏 𝜆𝑧.𝑧
完整的lambda项
(𝜆𝑥.(𝜆𝑦.(((𝑦 𝑥) 𝑎) 𝑏)))
(((𝜆𝑥.(𝜆𝑦.(𝑦 𝑥))) 𝑎) 𝑏)
(𝜆𝑔.((𝜆𝑥.(𝑔 (𝑥 𝑥))) (𝜆𝑥.(𝑔 (𝑥 𝑥)))))
(𝜆𝑥.(𝜆𝑦.((𝑎 𝑏) (𝜆𝑧.𝑧))))
在后面演算的时候,将括号复原是非常重要的事情
定义2:语法全等
我们用恒等号来表示两个lambda项完全相同,即他们具有完全相同的结构,对应位置上的变量也完全相同,就像矩阵全等一样
定义3:自由变量
对一个 𝜆 项 𝑃,我们可以定义 𝑃 中自由变量的集合 FV(𝑃) 如下:
- FV(𝜙) = {𝜙}
- FV(𝜆𝜙.𝑀) = FV(𝑀) \ {𝜙}
- FV(𝑀 𝑁 ) = FV(𝑀) ∪ FV(𝑁 )
从第 2 可以看出抽象 𝜆𝜙.𝑀 中的变量 𝜙 是要从 𝑀 中被排除出自由变量这个集合的。若 𝑀 中有𝜙,我们可以说它是被约束的。据此可以进一步定义约束变量集合。值得注意的是,对同一个 𝜆 项来说,这两个集合的交集未必为空。
几个简单的例子:
𝜆 项 𝑃的 自由变量集合 FV(𝑃)
𝜆𝑥.𝜆𝑦.𝑥 𝑦 𝑎 𝑏的自由变量集合 {𝑎, 𝑏}
𝑎 𝑏 𝑐 𝑑 的自由变量集合{𝑎, 𝑏, 𝑐, 𝑑}
𝑥 𝑦 𝜆𝑦.𝜆𝑥.𝑥 的自由变量集合{𝑥, 𝑦}
(注意,在第四个例子中,\y.\x.x中被约束的变量确实是x y,但是这和开头的x y不同,因为\y.\x.x同样可以写成\a.\b.b,这就像f(x)可以写成f(a)一样,抽象中的𝜙只是一个符号而已,但是符号的重复会给计算带来很大的困难,建议还是使用不同的𝜙。另一方面,如果对于lambda项P来说,FV(P) = ∅,则称 P 是 封闭的,这样的 P 又称为组合子。)
定义4:出现
对于 𝜆 项 𝑃 和 𝑄,可以定义一个二元关系出现。我们说 𝑃 出现在 𝑄 中,是这样定义的:
- 𝑃 出现在 𝑃 中;
- 若 𝑃 出现在 𝑀 中或 𝑁 中,则 𝑃 出现在 (𝑀 𝑁 ) 中;
- 若 𝑃 出现在 𝑀 中或 𝑃 ≡ 𝜙,则 𝑃 出现在 (𝜆𝜙.𝑀) 中。
定义5:替换
对任意 𝑀, 𝑁, 𝜙,定义 [𝑁/𝜙] 𝑀 是把 𝑀 中出现的自由变量 𝜙 替换成 𝑁 后得到的结果,这个替换有可能改变部分约束变量名称以避免冲突。
其实在原文本中给出了7个非常抽象的例子,在这里笔者用简单的语言来描述一下这里发生了什么事情
对于\f.\x. f (\f.\x.x) f x这个lambda项来说,有些人会把f或者(f x)当成一个lambda项替换开头的\f.\x,这是不可以的(但可以替换它前一个括号里的抽象),因为在这个lambda项的真实表达式(即补满了括号)中,f x均是约束变量,不能替换自己,另一方面,lambda项中的变量都是假变量,即都是无意义的符号变量,就像定积分中的
一样,你把x换成t或者别的不影响任何事情。
说到底,lambda演算还是一种解释性的语言,它并不要求计算出任何具体的数值,而是去解释这个函数/抽象,并且可以随意替换。
定义 6:𝛼 变换和 𝛼 等价
设 𝜆𝜙.𝑀 出现在一个 𝜆 项 𝑃 中,且设 𝜓 ∉ FV(𝑀),那么把 𝜆𝜙.𝑀 替换成𝜆𝜓.[𝜓/𝜙] 𝑀
的操作被称为 𝑃 的 𝛼 变换。当且仅当若 𝑃 经过有限步(包括零步)𝛼 变换后,得到新的 𝜆 项 𝑄,则我们可以称 𝑃 与 𝑄 是 𝛼 等价的。
这个就是上面说的假变量
定义 7:𝛽 规约
形如(𝜆𝜙.𝑀) 𝑁的 𝜆 项被称为 𝛽 可约式,对应的项[𝑁/𝜙] 𝑀则称为 𝛽 缩减项。当 𝑃 中含有 (𝜆𝜙.𝑀) 𝑁 时,我们可以把 𝑃 中的 (𝜆𝜙.𝑀) 𝑁 整体替换成 [𝑁/𝜙] 𝑀,用 𝑅指称替换后的得到的项,那么我们说 𝑃 被 𝛽 缩减为 𝑅,当 𝑃 经过有限步(包括零步)的 𝛽 缩减后得到 𝑄,则称 𝑃 被 𝛽 规约到 𝑄
这个就是刚刚说的替换的事情
到这里,整个lambda演算的体系已经基本建立起来了,只需要再定义一些ZERO,ADD,POW,TRUE,FALSE等的lambda项即可,也即程序设计语言。
ZERO = \f.\x.x
SUCC =\n.\f.\x.f(n f x)
PLUS = \m.\n.m SUCC n
MULT = \m.\n.\f.m(n f)
POW = \b.\e.e b
PRED = \n.\f.\x.n(\g.\h.h(g f))(\u.x)(\u.u)
SUB = \m.\n.n PRED m
一个简单的例子
SUCC ZERO
• \n.\f.\x.f (n f x) \f.\x.x
• \f.\x.f (\f.\x.x) f x
• \f.\x.f x
TREU = \x.\y.x
FALSe = \x.\y.y
AND = \p.\q.p q p
OR = \p.\q.p p q
NOT = \p.\a.\b.p b a
IF = \p.\a.\b.p a b
ISZERO = \n.n(\x.FALSE)TRUE
LEQ = \m.\n.ISZERO(SUB m n)[如果GEQ将m n 交换了位置]
EQ = \m.\n. AND(LEQ m n)(LEQ n m)
到这里,Lambda里面的基本定义和易错易混的地方笔者已经全部解释清楚了。接下来还有一个叫不动点的概念,主要是用来处理递归/迭代的Lambda表达式的双重应用。
Y = \g.(\x.g (x x))\x.g(x x)
YF = (\g.(\x.g (x x))\x.g(x x)) F
= (\x.F (x x))\x.F(x x)
= F(\x.F(x x))(\x.F(x x))
= F(YF)
最后把软工一的十道题放上来,供大家练习和参考。
1.I = \x.x
S = \x.\y.\z.x z(y z)
I =S I = \x.\y.\z.x z(y z) \x.x
=\y.\z. (\x.x)z(y z)
=\y.\z. z(y z)
I m n = \y.\z.z(y z) m n
= n (m n)
2.ZERO = \f.\x.x
SUCC = \n.\f.\x.f(n f x)
SUCC(SUCC ZERO)=SUCC(\n.\f.\x.f(n f x) \f.\x.x)
=SUCC(\f.\x.f(\f.\x.x)f x)
=SUCC(\f.\x.f x)
=\n.\f.\x.f(n f x) (\f.\x.f x)
=\f.\x.f (\f.\x.f x)f x
=\f.\x.f f x
3.POW = \b.\e.e b(TWO = \f.\x.f f x THREE = \f.\x.f f f x)
POW TWO THREE=\b.\e.e b TWO THREE
=THREE TWO
=\f.\x. f(f(f(x))) TWO
=\x. TWO(TWO(TWO(x)))
=\x. TWO(TWO(\a.\b. a(a(b)) (x))
=\x. TWO(TWO \b. x(x(b))
=\x. TWO((\c.\d. c(c(d))(\b. x(x(b)) ))
=\x. TWO(\d. (\b. x(x(b)) ( \b. x(x(b)) d ) ) )
=\x. TWO(\d. (\b. x(x(b)) ( \b. x(x(b)) d ) ) )
=\x. TWO(\d. (\b. x(x(b)) ( x(x(d)) ) ) )
=\x. TWO(\d. (x(x(x(x(d))))) )
=\x. \e.\f. e(e(f)) (\d. (x(x(x(x(d))))) )
=\x. \f. (\d. (x(x(x(x(d))))) ) ( ( \d. (x(x(x(x(d))))) ) f))
=\x. \f. (\d. (x(x(x(x(d))))) ) (x(x(x(x(f)))))
=\x. \f. (x(x(x(x(x(x(x(x(f)))))))))
=\f. \x. (f(f(f(f(f(f(f(f(x)))))))))
-
NOT(NOT TRUE)=(\p.\a.\b.p b a)((\p.\a.\b.p b a)(\x.\y.x))
=(\p.\a.\b.p b a)((\a.\b.(\x.\y.x) b a))
=(\p.\a.\b.p b a)(\a.\b.b)
=(\a.\b.(\a.\b.b) b a)
=(\a.\b.a)= TRUE
IF(OR FALSE FALSE)a b=IF((\p.\q.p p q)(\x.\y.y)(\x.\y.y))a b
=(\p.\a.\b.p a b)((\p.\q.p p q)(\x.\y.y)(\x.\y.y))a b
=(\p.\a.\b.p a b)((\x.\y.y)(\x.\y.y)(\x.\y.y))a b
=(\p.\a.\b.p a b)(\x.\y.y)a b
=\x.\y.y a b
=b -
LEQ=\m.\n.ISZERO(SUB m n)
GEQ =NOT LEQ
=(\p.\a.\b.p b a) LEQ
=\a.\b (\m.\n ISZERO(SUB m n)) b a
=\a.\b(ISZERO(SUB b a)) -
FACT1 =\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))
FACT = FACT1 FACT1
FACT THREE = FACT1 FACT1 THREE
=\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) \f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) THREE
=IF(ISZERO THREE)ONE(MULT THREE (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) \f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (PRED THREE)))
=(MULT THREE (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) \f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (PRED THREE)))
=(MULT THREE (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) \f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) TWO))
=(MULT THREE (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) \f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) TWO))
=(MULT THREE (IF(ISZERO TWO)ONE(MULT TWO ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (PRED TWO))))
=(MULT THREE TWO ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (PRED TWO))))
=(MULT THREE TWO ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))ONE)))
=(MULT THREE TWO ((IF(ISZERO ONE)ONE(MULT ONE ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))ONE) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))))(PRED ONE))) ))
=(MULT THREE TWO (MULT ONE ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))ONE) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))))(PRED ONE))) ))
=(MULT THREE TWO (MULT ONE ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))ONE) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n))))ZERO))))
=(MULT THREE TWO (MULT ONE ((IF(ISZERO ZERO)ONE(MULT ZERO ((\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))) (\f.\n.IF(ISZERO n)ONE(MULT n (f f (PRED n)))) (PRED n)))ONE) ))))
=(MULT THREE TWO (MULT ONE ONE))
=\f.\x f f f f f f x
7.ADD = W(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))
ADD TWO FOUR = W(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) TWO FOUR
= \x.x (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) TWO FOUR
= (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) TWO FOUR
=(IF(ISZERO FOUR)TWO((\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(SUCC TWO)(PRED FOUR)))
=IF(ISZERO FOUR)TWO((\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(THREE)(THREE))
=(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) THREE THREE
=IF(ISZERO THREE)THREE((\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(SUCC THREE)(PRED THREE))
=(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))FOUR TWO
=IF(ISZERO TWO)FOUR((\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(SUCC FOUR)(PRED TWO))
=(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))FIVE ONE
=IF(ISZERO ONE)FIVE((\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(SUCC FIVE)(PRED ONE))
=(\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))SIX ZERO
=IF(ISZERO ZERO)SIX((\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m))) (\f.\n.\m.IF(ISZERO m)n(f f(SUCC n)(PRED m)))(SUCC SIX)(PRED ZERO))
=SIX = \f.\x f f f f f f x
8.FACT2 =\f.\n. IF(ISZERO n)ONE(MULT n(f (PRED n)))
FACTY = Y FACT2
FACTY THREE = Y FACT2 THREE
=FACT2(Y FACT2) THREE
=\f.\n. IF(ISZERO n)ONE(MULT n(f (PRED n)))(Y FACT2)THREE
=IF(ISZERO THREE)ONE(MULT THREE (Y FACT2 (PRED THREE)))
=IF(ISZERO THREE)ONE(MULT THREE (FACT2(Y FACT2)(TWO)))
=MULT THREE (FACT2(Y FACT2) TWO)
=MULT THREE (IF(ISZERO TWO)ONE(MULT TWO (Y FACT2 (PRED TWO))))
=MULT THREE (MULT TWO (Y FACT2 (ONE)))
=MULT THREE (MULT TWO (MULT ONE (Y FACT2 ZERO)))
=MULT THREE (MULT TWO (MULT ONE ONE))
=MULT THREE (MULT TWO ONE)
=MULT THREE TWO
=\f.\x. f f f f f f x
-
CAR = \p.p TRUE
CDR =\p.p FALSE
TRUE = \x.\y.x
FALSE =\x.\y.y
CAR(CDR(CONS a(CONS b(CONS c NIL))))=\p.p TRUE (\t.t FALSE(CONS a(CONS b(CONS c NIL))))
=\p.p TRUE(\t.t (\x.\y.y)(CONS a(CONS b(CONS c NIL))))
=\p.p TRUE(\x.\y.y CONS a(CONS b(CONS c NIL)))
=\p.p TRUE(CONS b(CONS c NIL))
=\x.\y.x (CONS b (CONS c NIL))
= b -
LENGTH NIL =LENGTH \x.TRUE
=Y (\g.\c.\x. NULL x c (g (SUCC c) (CDR x))) ZERO NIL
=Y F ZERO \x.TRUE
=(\g.\c.\x. NULL x c (g (SUCC c) (CDR x)))(Y F )ZERO NIL
=NULL NIL ZERO (Y F(SUCC ZERO)(CDR NIL))
=(\p.p(\x.\y.FALSE)) NIL ZERO(Y F(SUCC ZERO)(CDR NIL))
=(\x.TRUE(\x.\y.FALSE))ZERO(Y F(SUCC ZERO)(CDR NIL))
=\x.\y.x ZERO (Y F(SUCC ZERO)(CDR NIL))
=ZERO