基本规则#
在lambda演算中,只有三项事物:
- 变量,Variable,这里它可以是抽象的任何事物,使用x,y,z来表示。
- 抽象,Abstract,它是一个完整的函数定义,用λ开头作为变量,后面跟着表达式。
- 应用,Application,它指的是,把函数抽象应用在参数上。
例如,类似于λxy→xy这样的表达式就是一个lambda,里面的x
和y
就是变量,但是要注意的是,右边的xy
不是x跟y相乘的意思,而是把x
的抽象应用到y
上。
假设我们已经有一个抽象,用succ
来标记,然后有一个自然数0,我们可以把上面的λxy→xy,给应用到succ
和自然数0上:
(λxy→xy) succ 0这里面,我们把lambda右边的x替换为succ
,y替换为0,就得到succ 0,就是1。
修改一下数学表达方式#
你可能会很奇怪,这到底有什么用?为了要描述清楚这个问题,我需要前面的数学表达方式稍微调整一下,否则一会会非常混乱。
我们给每一个参数前面加一个λ符号,每个参数用.
分隔,然后用一个箭头→,后面跟着抽象表达。
对于前面的例子,写成这样:
λx.λy→x(y)需要额外一提的是,如果一个函数的参数和抽象的形式是一样的,那么着两个函数就是一样的,而不需要考虑字符是否相同,例如下面的两个函数是一样的函数。
λx.λy→x yλa.λb→a b然后,忘掉前面自然数和succ的这个例子,我们用纯粹的lambda演算来定义一些东西。
丘奇数#
我们从很小的时候就学过算数,从小学一年级的第一堂课起,我们就知道了自然数这个东西,有没有思考过这样一件事,就是到底什么是数,0是什么,1又是什么?
对于这个问题的回答,每一种数学思考会得到不同的答案。在lambda演算这里,数可以代表这样一种东西,就是它本身就一个函数。把苹果带入3这个函数得到的是3个苹果,把x带入到2则得到2个x,至于这个x本身是什么,倒是无关紧要的东西。
把数看成是某种函数,这个就是丘奇数的想法,更具体一点数,丘奇规定了下面的丘奇数:
0ˉ1ˉ2ˉnˉ=λs.λx→x=λs.λx→s x=λs.λx→s (s x)...=λs.λx→s (sn−1 x)需要注意的是,这其中的s和x都是某种抽象,但是察觉s实际上是某种自增运算。由于它是一种抽象,所以这里定义出来的数都需要加上一个横杠。
然后,我们其实可以定义这种丘奇数的自增运算。它是下面的形式:
SUCC:=λn.λf.λx→f(n f x)我们尝试着进行SUCC 1
,来看看会发生什么:
succ 1ˉ=(λn.λf.λx→f(n f x))(λs.λx→s x)这里我们把前面的λn消去(因为带入了1个参数),把1ˉ带进到后面的n里面去,注意在后面的f ( n f x)
里面,把n换掉之后,就变成了
f(n f x)=f((λs.λx→s x) f x)=f (f x)所以succ 1ˉ就变成了:
succ 1ˉ=λf.λx→f (f x)我们可以发现,正好就是2ˉ的形式,因此,证明了succ 1ˉ=2ˉ。
类似地同理可以证明succ nˉ=n+1,具体的证明过程这里不详细写了。
丘奇还给了两个丘奇数相加的函数,是下面的形式:
add:=λm.λn.λf.λx.→m f (n f x)具体的证明过程这里不详细证了。
丘奇数的意义#
现实生活中的自然数当然不可能使用丘奇数,但是对于数学分析或者实分析比较了解的人,看到前面的过程应该能够很快理解丘奇数厉害在哪里,至少应该能否很快反应过来,就是丘奇数与自然数是同构的,这里的同构指的是范畴上的同构,这个证明过程虽然可能比较复杂,但是道理却很容易想明白。
一旦确定了丘奇数和自然数的同构关系,那么任何自然数域中得到的结论,在丘奇数中也会有一个镜像的结论。但不要忘记,任何一个丘奇数都是二元函数这个事情。
布尔值与IF#
有丘奇数这个例子在前面,我们可以定义出更多的东西出来,例如bool值:
TrueFalse:=λx.λy→x:=λx.λy→y有了IF之后,也可以定义出IF条件判断:
IF:=λb.λx.λy→b x y来尝试带入IF True 2ˉ 5ˉ试一下:
IF True 2ˉ 5ˉ=(λb.λx.λy→b x y) True 2ˉ 5ˉ=True 2ˉ 5ˉ=(λx.λy→x) 2ˉ 5ˉ=2ˉFor循环#
依靠lambda演算,也可以定义出for循环,把for循环理解为三个参数的函数,第一个参数是n,需要代入丘奇数,作为循环的次数,第二个参数是f,代表重复应用的函数,第三个参数是x,代表对谁进行重复应用,for循环可以定义成下面这样:
For:=λn.λf.λx→n(λg.λy→g (f y)) Id x其中的Id表示的是恒等映射,形式为:
Id:=λx→x这里关键是我们要弄懂中间的n(λg.λy→g (f y)) Id,仍然要注意这里的n需要代入丘奇数,我们可以先代入一个0ˉ试一下,0ˉ的定义是λs.λx→x,那么这样一来,(λs.λx→x)(λg.λy→g (f y)) Id得到的就是Id,也就是循环了0次就等于没有循环。
代入1ˉ试一下,1ˉ=λs.λx→s x,那么(λs.λx→s x)(λg.λy→g (f y)) Id,得到的是(λg.λy→g (f y)) Id,这里面把g代入Id,得到就是f y,这样一来的话:
(λs.λx→s x)(λg.λy→g (f y)) Id=(λg.λy→g (f y)) Id=λy→f y注意这里面其实出现了一个闭包的问题,这里我们暂时不讨论这个,只需要知道最终出现的是λy→f y,把x代入自然得到的就是f x。
也就是说当1ˉ代入n的时候,得到的确实是把f应用到x一次的结果。
那如果代入的是2ˉ呢,这个时候就不是把(λg.λy→g (f y))应用到Id了,而是应用到刚才得到的λy→f y,可以得到λy→f (f y),也就是把参数应用两次f函数之后的结果。
依次类推,可以知道代入nˉ得到的就是循环n次得到的结果。