神奇的λ演算
函数是一个强大的概念,很多理论都是以这种形式构建起来的。比如定理可以定义成函数的形式,有输入,输出,以及一系列过程,过程中又是由多个子定理构成 的,不断深入展开最后达到的是作为原子函数的公理。有些颇具魅力的函数,比如可以判断某程序是否死循环的程序,开发商要是发明出这种软件绝对可以发笔大 财。可是事实上科学家逐渐发现有些问题根本无法计算或者说找不出这样的函数,图灵已经用类似对角法的证明否定了刚才那种程序的存在,也就是所谓的停机问 题。
直到1930与图灵齐名的天才丘奇提出了λ演算,我们才走上了可计算理论研究之路。λ演算真的是让人耳目一新的理论,整套系统只定义 了三条规则,却能变化出许多令人称奇的精彩表演,这真让人感慨真理具有的简单之美。λ演算中最关键的要素就是函数被当作变量处理,能够参与运算。我们这样 来思考,想要将某个函数f(x)变量化,势必要构建一个高于函数的平台能够让函数作为另一个更抽象的存在的输入,即所谓高阶函数的概念。在λ演算里用 λx.f(x)的形式表达这样的概念,λx依然是一个函数,比如我们输入3就是将变量替换成3,表示成
λx.f(x)3 = f(3)
如 果f(x)是一个取倒数函数 ,f(3) = 1/3
这种概念看上去很多余为什么不直接使用f(x)而要麻烦的多转个弯呢。为了解释这种 形式的威力之前,先来看看一些有趣的现象。大家猜猜这是个什么函数
(λx.x 3)(λx.2+x)
依次代 (λx.2+x)进函数(λx.x 3),根据前面的介绍,任何形式λx的函数都可以接受其他函数作为参数。得到
λx.2+x 3
继 续将3代入函数λx.2+x得到2+3=5
原来是一个常数,是不是很有趣,这神奇之处就在于λ演算允许函数可以像变量一个样的传递然后继 续运算。
有了这样一个规则简单的系统,现在看一下能够在这个基础上构建一些什么
退回到最原始的λ演算只有三个公理,并没 有定义任何整数,也没有加法。
如果定义自然数为
0 = λfx.f x #是λf.(λx. f x)的缩写
1 = λfx.f x
2 = λfx.f (f x)
当然我们也可以有任何其他的形式来定义这些数,公理系统的精髓就在 于能够自圆其说,并不局限于长什么样子。
函数f(x)=x+1就可以定义成
λ n f x. f (n f x)
别 管他是怎么想出来的,先来验证一下代入1会是多少
根据定义λfx.f x是1的定义,代入替换n之后,
λfx.f((λfx.f x) f x)
λfx.f((λx.f x) x)
λfx.f(fx)
这个正是2的定义,看来这个 x+1的函数工作的非常好。 虽然有些繁琐,但是这个系统真的可以构建很多概念,包括四则运算,布尔运算等等。从直觉上讲,λ系统是由函数以及函数运算特性作为最小信息的载体组成的, 对比一下计算机系统是由01和布尔运算作为最小信息的载体。
再来看一个有趣的函数λf.(λx.f(x x))(λx.f(x x))
因为这个函数的特殊性我们给他一个名字叫做Y 或者Y Combinator(Y组合算子)
如果我们用任何g代入 这个函数,
Yg
= (λx.g(x x))(λx.g(x x))
=g((λx.g(x x)) (λx.g(x x)))
=g(Yg)
换句话说函数f=Yg这样一个函数可以无限扩充函数g
f=g(f)=g(g(f))=gggf=...
这 样的f称之为g的不动点,形象的说明了这一特性,并且这种形式蕴含着某种递归的性质。
一点都没有错Y可以帮助我们来进行递归定义。
举 个例子,看一下阶乘FAC的定义,FAC= λx.n=0?1:FAC(n-1)
然而这种定义在λ中不是有效的,因为λ 并不支持命名函数,这里的FAC只是我们能够理解的概念。怎么办呢?关键的时候回想一下λ演算的精髓,函数可以当作变量来用。这里FAC是我们假设的某个 具体函数,如果把它抽象出来作为未知的量,就像是建立一元一次方程一样,会怎么样呢?
FAC=(λf.λn.n=0?1:n*f(n-1))FAC
令 人惊奇的是,FAC左边已经是一个有效的λ函数了,简写为M。
FAC=M FAC
比较一下不动点的定义
f=g(f) f是g的不动点
显然FAC是M的不动点
又因为f=Yg是这样一个不动点
所以FAC= Y M = Y (λf.λn.n=0?1:n*f(n-1)),到此为止我们居然已经求出FAC的λ函数了。
虽然很怀疑自己的眼睛,这真的是新大陆 吗?让我们代入一个数字,看看自己是不是在做梦吧。
FAC 2=(Y M) 2
因为Y M是M的不动点所以
(Y M)2 = M(Y M)2
((λf.λx.n=0?1:n*f(n-1))(Y M))2
(λn.n=0?1:n*((Y M)(n-1))))2
2*((Y M)(2-1))
2*((Y M)1)
2*(M(Y M)1)
2*((λf.λx.n=0?1:n*f(n-1))(Y M)1)
2*(λn.n=0?1:n*((Y M)(n-1)))1)
2*(1*((Y M)0))
2*(1*(λn.n=0?1:n*((Y M)(n-1)))0))
2*(1*(1))
整个的计算过程有些复杂但确实是一个完美的递归定义。我们再来验证更大一 点的数,比如4
这次换一种计算方式,先展开不动点4次
(MMMM(Y M))4
4*(MMM(Y M)3)
4*3*(MM(Y M)2)
4*3*2*(M(Y M)1)
4*3*2*1(M(Y M)0)
4*3*2*1*1
其实这种展开形 式已经让人非常确信这就是一个递归了。
References
直到1930与图灵齐名的天才丘奇提出了λ演算,我们才走上了可计算理论研究之路。λ演算真的是让人耳目一新的理论,整套系统只定义 了三条规则,却能变化出许多令人称奇的精彩表演,这真让人感慨真理具有的简单之美。λ演算中最关键的要素就是函数被当作变量处理,能够参与运算。我们这样 来思考,想要将某个函数f(x)变量化,势必要构建一个高于函数的平台能够让函数作为另一个更抽象的存在的输入,即所谓高阶函数的概念。在λ演算里用 λx.f(x)的形式表达这样的概念,λx依然是一个函数,比如我们输入3就是将变量替换成3,表示成
λx.f(x)3 = f(3)
如 果f(x)是一个取倒数函数 ,f(3) = 1/3
这种概念看上去很多余为什么不直接使用f(x)而要麻烦的多转个弯呢。为了解释这种 形式的威力之前,先来看看一些有趣的现象。大家猜猜这是个什么函数
(λx.x 3)(λx.2+x)
依次代 (λx.2+x)进函数(λx.x 3),根据前面的介绍,任何形式λx的函数都可以接受其他函数作为参数。得到
λx.2+x 3
继 续将3代入函数λx.2+x得到2+3=5
原来是一个常数,是不是很有趣,这神奇之处就在于λ演算允许函数可以像变量一个样的传递然后继 续运算。
有了这样一个规则简单的系统,现在看一下能够在这个基础上构建一些什么
退回到最原始的λ演算只有三个公理,并没 有定义任何整数,也没有加法。
如果定义自然数为
0 = λfx.f x #是λf.(λx. f x)的缩写
1 = λfx.f x
2 = λfx.f (f x)
当然我们也可以有任何其他的形式来定义这些数,公理系统的精髓就在 于能够自圆其说,并不局限于长什么样子。
函数f(x)=x+1就可以定义成
λ n f x. f (n f x)
别 管他是怎么想出来的,先来验证一下代入1会是多少
根据定义λfx.f x是1的定义,代入替换n之后,
λfx.f((λfx.f x) f x)
λfx.f((λx.f x) x)
λfx.f(fx)
这个正是2的定义,看来这个 x+1的函数工作的非常好。 虽然有些繁琐,但是这个系统真的可以构建很多概念,包括四则运算,布尔运算等等。从直觉上讲,λ系统是由函数以及函数运算特性作为最小信息的载体组成的, 对比一下计算机系统是由01和布尔运算作为最小信息的载体。
再来看一个有趣的函数λf.(λx.f(x x))(λx.f(x x))
因为这个函数的特殊性我们给他一个名字叫做Y 或者Y Combinator(Y组合算子)
如果我们用任何g代入 这个函数,
Yg
= (λx.g(x x))(λx.g(x x))
=g((λx.g(x x)) (λx.g(x x)))
=g(Yg)
换句话说函数f=Yg这样一个函数可以无限扩充函数g
f=g(f)=g(g(f))=gggf=...
这 样的f称之为g的不动点,形象的说明了这一特性,并且这种形式蕴含着某种递归的性质。
一点都没有错Y可以帮助我们来进行递归定义。
举 个例子,看一下阶乘FAC的定义,FAC= λx.n=0?1:FAC(n-1)
然而这种定义在λ中不是有效的,因为λ 并不支持命名函数,这里的FAC只是我们能够理解的概念。怎么办呢?关键的时候回想一下λ演算的精髓,函数可以当作变量来用。这里FAC是我们假设的某个 具体函数,如果把它抽象出来作为未知的量,就像是建立一元一次方程一样,会怎么样呢?
FAC=(λf.λn.n=0?1:n*f(n-1))FAC
令 人惊奇的是,FAC左边已经是一个有效的λ函数了,简写为M。
FAC=M FAC
比较一下不动点的定义
f=g(f) f是g的不动点
显然FAC是M的不动点
又因为f=Yg是这样一个不动点
所以FAC= Y M = Y (λf.λn.n=0?1:n*f(n-1)),到此为止我们居然已经求出FAC的λ函数了。
虽然很怀疑自己的眼睛,这真的是新大陆 吗?让我们代入一个数字,看看自己是不是在做梦吧。
FAC 2=(Y M) 2
因为Y M是M的不动点所以
(Y M)2 = M(Y M)2
((λf.λx.n=0?1:n*f(n-1))(Y M))2
(λn.n=0?1:n*((Y M)(n-1))))2
2*((Y M)(2-1))
2*((Y M)1)
2*(M(Y M)1)
2*((λf.λx.n=0?1:n*f(n-1))(Y M)1)
2*(λn.n=0?1:n*((Y M)(n-1)))1)
2*(1*((Y M)0))
2*(1*(λn.n=0?1:n*((Y M)(n-1)))0))
2*(1*(1))
整个的计算过程有些复杂但确实是一个完美的递归定义。我们再来验证更大一 点的数,比如4
这次换一种计算方式,先展开不动点4次
(MMMM(Y M))4
4*(MMM(Y M)3)
4*3*(MM(Y M)2)
4*3*2*(M(Y M)1)
4*3*2*1(M(Y M)0)
4*3*2*1*1
其实这种展开形 式已经让人非常确信这就是一个递归了。
--end--
λ演算有它纯数学晦涩难懂 的一面,更有纯数学那种优美所带给人的心驰神往。
References
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步