Lambda表达式与图灵完备
引子
这篇还是用中文写吧。我基本上没有看到中文的推导过程。当然英文的也各种缺失推导过程。有空的话再用英文写一篇(我肯定没有空)。
首先是lambda表达式。用过Python, Java, JS的,都应该知道。否则意味着你肯定没有好好学。
我是从国外的视频中看到lambda表达式和图灵机等价这一观点的。然后人家就进行了简单的推导。然而我根本就看不懂。我很怀疑我的英语水平,于是又仔细看了几遍视频,仍然不懂。我觉得我需要研究一下,因为视频中的很多推导都明白了。但是就有一步推导,讲解者说了这过程比较复杂,然后就带过了。我非常想知道这推导过程怎么来的。所以搜索了许多资料,加上自己的思考,写了下面的文字。
图灵完备
图灵完备是个什么意思?通俗的意思就是能实现正整数加减法,if判断跳转,while循环,以及可以构造简单数据结构的都称为图灵完备。图灵完备的语言无法处理停机问题。具备图灵完备的假象机器就是图灵机。你认为正整数加减法,if判断跳转,while循环很简单,所以你这个人也是图灵机的一种。
所有编程语言都会将图灵完备作为最基础的目标。你看比特币智能合约这么火,它也说自己是图灵完备的。这样看来图灵完备是检测这门编程语言是否能通用的前提。当然Java、Python、JS等等都是图灵完备的。
lambda表达式
在推导之前先看看什么是lambda表达式。
1 | f(x) -> x |
我认为以上都是lambda表达式。其中f,x都是变量,不光可以代表值还可以代表函数。f(x)代表一次f对x的调用。-> 是说最终得到x, 或者结果为x.
lambda表达式图灵完备推导
下面开始推导,首先的前提条件是赋值和等价这两个操作是最初存在的。为什么要提这个事情呢?因为不提这个事情就无法进行if的判断,也没有办法得到结果。其实图灵机的定义中其实也暗含了赋值和等价判断这两个基础操作。所有人都认为理所当然,只有我特意将这两个操作提出来。
推导之前我们必须有的基础操作
- 赋值
- 判断等价
- 调用,使用**()表示,也可以使用.**表示
另外我们还应该清楚一件事,就是单参lambda完全等价于多参lambda表达式。在最初的1920+年Church这伟大的人物提出来lambda的时候就是使用的单参。但是我们为了推导方便,我故意使用多参。
问题: 多参为什么等价于单参lambda?
答:
1 | f(x,y) -> z |
下面开始真正的推导:
首先定义True与False
1 | False: x -> x , 这样写你是不是更明白? (f,x) -> x |
然后就可以定义IF判断了。你看看False的定义是不是就是False ? f : x
. True的定义是不是True ? f : x
.所以False返回了x,而True返回f.我们将IF定义为多元组
1 | IF(False,f,x) -> x |
下面我们再来定义正整数。False在我们计算机界经常被认为是0.所以我们0的定义就是
1 | 0: f,x -> x |
正整数1的定义,我们认为调用了一次f,即
1 | 1: f,x -> f(x) |
下面正整数2,3…,n的定义就是
1 | 2: f,x -> f(f(x)) |
我们下面为了更加方便我们这样简写:
1 | 2: f,x -> 2.f(x) |
我们下面来定义加法操作。例如n + m. 这个问题不好想,所以先想特例。例如5 = 2 + 3, 那么怎么得到5呢,就是5次函数调用:
1 | 5: f,x -> f(f(f(f(f(x))))) == f(f(f(2.f(x)))) == 3.f(m) == 3.f(2.f(x)) 其中2.f(x) 替换成m,然后再替换回来。 |
定义下乘法操作.例如n*m. 同样先想特例: 6 = 3 * 2. 怎么得到6呢?
1 | 6: f,x -> f(f(f(f(f(f(x)))))) == 2.f(2.f(2.f(x))) == 3.2.f(x) 其中2.f(x)替换为z所以就变成了3.z(x) 再替换回来就是3.2.f(x) |
下面是定义n++操作,这个在数学上叫做Successor,所以我叫这个lambda为Succ. 其实从n到n+1是很简单。
1 | Succ: n,f,x -> f(n.f(x)) 就是多调一次f就行了 |
下面是定义n–操作,这个在数学上叫做Predecessor. 这个是最复杂的。我看视频就是没看懂这里。问题是怎么从n变成n-1。我知道n-1怎么变成n。那有没有方法将n-1带入公式,最后再同时消除呢?就这么干!当年Church可是苦想n天。我辈比较幸运,直接知道人家的想法了。看这篇文章的你们就更加幸运,因为我把所有被省略的推理过程也写出来了。
1 | 先定义: PSucc(n) -> (Snd n,Succ(Snd n)) |
现在好办了,只要有了加减法,所有的一切操作就都好办了。
1 | n-m的减法就是执行n--操作m次。 |
下面再定义一些AND,OR,NOT就非常简单了
1 | AND(a,b) -> IF(a,b,False) 这个意思就是如果a是真的,那就看b是不是真的。否则,那一定返回False. |
下面再定义while循环
1 | WHILE(n,f) -> n.f |
再来定义点简单的数据结构,例如链表, 这里还是学习了一下Lisp
1 | > (cons 1 2) |
cons代表的是构建一个链表。 car代表是前一个节点,cdr代表的是后一个节点。那么我们用lambda表达式也写一个。
1 | 构造链表cons: cons(a,b) -> (a,b) |
我们将0判断、False判断、null判断这三种操作认为是等价的。文章开始也说了,等价判断是先决条件。所以0判断一定是预先存在的。所以lambda表达式图灵完备了。
再说一点,图灵完备,意味着无法停机。停机证明不是本文的重点,不再证明。(对对对,就是笔者不会证明。你们随便吐槽)
总结
看了这篇文章你能学习到什么?你能证明1+2 == 3 ?还是会写链表了?lambda证明到底有什么用?根本就没有编程来的实在!你说的太对了。我也这样认为。那这篇文章到底有什么用?
就是为了装逼呀!!!
你看blockchain智能合约这么火,最后还不忘加上图灵完备
字样。为啥?为了装逼呀~~~学计算机的这么多人,懂得图灵完备没有几个,懂得怎么证明图灵完备估计也没有几个。以后你们大可以吹嘘自己知道如何证明图灵完备。
看到一条微博,说:“太难了,我大脑停机了。” 就回复:“你竟然不是图灵完备的!!”
以后有谁再说**“我无法思考了”**,你们就接话:“你竟然不是图灵完备的!!”
对,以后谁在你们面前装逼说自己会图灵完备的证明,你们就接话:“我也会!!”
这才是这篇文章的正确打开方式。