神奇的λ-calculus


高山仰止,景行行止。虽不能至,心向往之。

先人遗风

λ-calculus(英文做lambda calculus)于1930s由阿隆佐·邱奇所引入,彼时在数位天才思想家的推动下数理逻辑学科已初见成行,其中关于计算机数理逻辑的尤以戈特弗里德·莱布尼兹、乔治·布尔、格奥尔格·康托尔、大卫·希尔伯特、库尔特·哥德尔、艾伦·图灵、阿隆佐·邱奇等人备受推崇,紧随其后的冯·诺依曼、约翰·麦卡锡、丹尼尔·福瑞德曼等人亦令吾辈顶礼膜拜,他们的成果殷泽后世,歌功颂德、付梓文书都显得微不足道。

潜龙在渊

λ-calculus之所以有着诱人的魅力,在于它的简洁和强大。它可以被称为是最小的通用程序设计语言。它简洁到只包含两条变换规则:变量替换(笔者业余时间参译的魔法书繁体版中1.1.5节有对此的详细解释,贴出链接请看官们不吝斧正: 程序應用的置換模型、变量绑定以及一条函数定义方式。是的,没了。它的强大在于任何一个可计算函数都可以用它的形式来进行表达和求值,所以它是图灵完备的。相比今天各种流行程序语言中具有的以及时不时要新增的时髦语法和概念,基于λ-calculus发明的Lisp之流几乎让人觉得特别落后了(实际并不是这样,《黑客与画家》有对Lisp的高度褒奖,以及SICP使用Scheme,丹尼尔所著的各种Scheme书籍都是对Lisp的高度肯定)(Scheme是Lisp的一种方言)。

牛刀小试

λ-calculus表达式简短的语法规则使用BNF标记如下:

<expr> ::=  <constant>| <variable>| (<expr> <expr>)| (λ <variable>.<expr>)

其中

<constant>可以是诸如0、1这样的数字,或者预定义的函数: +、-、*等。

<variable>是x、y等这样的名字。

(<expr> <expr>)表示函数调用。左边的为要调用的函数,右边的为参数。

(λ <variable>.<expr>)被称为lambda抽象(lambda abstraction),用以定义新的函数。

β-reduction

一个用来定义新函数的简单的lambda abstraction可以如下表达:

λx.x

它代表着一个调用求值为传入参数的函数(加上括号等价: (λx.x)),这个简陋的lambda abstraction展示了变量替换规则和函数定义方式。对函数的调用标记为(假设传入参数3进行调用):

(λx.x)3

以上调用求值为3。函数调用中参数替换过程又被称为β-reduction

等价的Scheme代码为:

((lambda (x) x) 3)

等价的Python代码为:

(lambda x: x)(3)

可见Scheme的前缀式(s-表达式)与λ-calculus正有着异曲同工之妙。值得注意的是λ-calculus中的函数总是匿名(anonymously)的。

λx.x中λ为固定标记,标示着这是一个函数(function),紧随其后的x为这个函数的形式参数(formal parameters),.之后的x为这个函数的函数体。

α-conversion

λx.x稍微复杂点的函数定义可以记为:

λx.xy

复杂在哪呢?λx.xy需要引入变量绑定(variable binding)的规则。其中x被称为绑定变量(binding variable),而y则称为自由变量(free variable)。形式参数x的值将替换到在xy中的x上,而y的值却依λx.xy被调用时的上下文而定,这样的函数和其关联自由变量的引用作用域被称为闭包(closure)

λx.xy绑定变量x进行改名后可得到一个新的函数:

λz.zy

这个改写过程被称为α-conversion,因λx.xyλz.zy是等价的,故这两个函数可被视为α-equivalent

同理,如下lambda abstraction皆视为α-equivalent:

λx.xy = λw.wy = λt.ty = λz.zy

需要注意的λy.yy与上述lambda abstraction不等价,在α-conversion变换过程中不可将绑定变量与自由变量使用同样的名字标记。

柯里化

事实上在λ-calculus中总是只使用具有一个形式参数的函数,那具有多个形式参数的函数如何在λ-calculus中表达呢?例有如下函数:

λxy.x*x + y*y

可以将其改写为等价的如下函数:

λx.(λy.x*x + y*y)

这个过程被称为柯里化(currying),与之相反的过程称为反柯里化

分别对λxy.x*x + y*yλx.(λy.x*x + y*y)传入x(10)、y(5)进行调用:

(λxy.x*x + y*y)(10,5)
= 10*10 + 5*5
= 125((λx.(λy.x*x + y*y))(10))(5)
= (λy.10*10 + y*y)(5)
= 10*10 + 5*5
= 125

可以发现currying中基本都会使用到closure

霜刃初开

试着用λ-calculus来描述自然数(0,1,2,3,4,5…..)

设0为zero,suc(zero)表示1,suc(suc(zero))表示2,以此类推。在λ-calculus中通过lambda abstraction来定义zero:

λs.(λz.z)

通过上文的反柯里化可得:

λsz.z

1,即suc(zero)则为:

λsz.s(z)

2,即suc(suc(zero))则为:

λsz.s(s(z))

以此类推…

令suc,即s为:

s = λwyx.y(wyx)

则1,即suc(zero),为:

1 = λsz.s(z) = s(zero) = (λwyx.y(wyx))(λsz.z)

将w替换为λsz.z:

1 = λsz.s(z) = s(zero) = λyx.y((λsz.z)yx)

将s替换y:

1 = λsz.s(z) = s(zero) = λyx.y((λz.z)x)

将z替换为x:

1 = λsz.s(z) = s(zero) = λyx.y(x)

还记得α-conversion?(λsz.s(z)λyx.y(x)是α-equivalent的)

同理,则2,即suc(suc(zero)),为:

2 = λsz.s(s(z)) = s(s(zero)) = (λwyx.y(wyx))(λsz.s(z))
2 = λsz.s(s(z)) = s(s(zero)) = λyx.y((λsz.s(z))yx)
2 = λsz.s(s(z)) = s(s(zero)) = λyx.y((λz.y(z))x)
2 = λsz.s(s(z)) = s(s(zero)) = λyx.y(y(x))

以此类推,所冀成焉。

纳履踵决

最近读了马丁·戴维斯所著的《逻辑的引擎》,参译了SICP繁体版,呃……纯粹出于好玩:-),再次浅薄地研究了一下λ-calculus,深感其美,固有此文。

数理逻辑学如大海般博奥,λ-calculus虽只是其中一支汪洋,却也深不可测。小子自知才疏学浅,文中所记内容虽考证再三,但仍心有余悸,若有所述不当之处恳请行家里手不吝斧正。我的电邮地址:[shawhen2012@hotmail.com](mailto: shawhen2012@hotmail.com)。

神奇的λ-calculus相关推荐

  1. C++实用技巧(一) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客

    C++实用技巧(一) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客 C++实用技巧(一) 复杂的东西写多了,如今写点简单的好了.由于功能上的需要, ...

  2. 【改】[火光摇曳]神奇的伽玛函数(下)——markdown排版

    原作者:靳志辉 https://github.com/cosname/cosx.org/blob/master/content/post/2014-07-01-gamma-function-2.md ...

  3. 神奇的伽玛函数(下)

    转自: http://www.52nlp.cn/%E7%81%AB%E5%85%89%E6%91%87%E6%9B%B3%E7%A5%9E%E5%A5%87%E7%9A%84%E4%BC%BD%E7% ...

  4. 如何利用python画三棱锥_微积分,英文版数学书,Calculus,积分,Excel,自然常数e,Python,泰勒展开...

    标题写的挺长的. 我是个学渣,念过大学,学过高数,学的时候不甚懂,工作中也没实践,仅有的一点粗浅概念早就还给老师了. 因为儿子即将开始学前教育,未雨绸缪,我开始研究现在的义务教育有些什么内容,不知不觉 ...

  5. 一段神奇的c代码错误分析

    源代码 #include <stdio.h>int main(int argc, char* argv[]) {int i = 0;int arr[3] = {0};printf(&quo ...

  6. python deque双端队列的神奇用法

    python中的deque双端队列,类似list的任意一端都可实现较快的add和pop操作 from collections import dequed=deque(maxlen=20) for i ...

  7. 几行代码实现神奇移动的过渡动画

    1.效果如图: 2.实现: 假设需求为如上图,点击ViewController01后,ViewController01上的两张图片,移动到ViewContoller02中,其实两个ViewContro ...

  8. Hudson神奇的环境变量

    Hudson神奇的环境变量 http://blog.sina.com.cn/s/blog_798f21a00100z6zw.html 转载于:https://blog.51cto.com/mylove ...

  9. 神奇的输入 while(cin....)如何在遇见换行之后进入下一层循环读入

    1 cin>>m>>n; 2 for(int i=1;i<=m;i++) { 4 int x=0; 5 char ch=' '; 6 while(ch!=10) //在遇 ...

  10. 【NOIP2015提高组Day1】 神奇的幻方

    [问题描述] 幻方是一种很神奇的 N*N矩阵:它由数字1,2,3, - - ,N*N 构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在 ...

最新文章

  1. QRadioButton 使用方法
  2. JS 二级菜单栏的tab切换
  3. mysql 5.7优化不求人_《MySQL 5.7优化不求人》直播精彩互动
  4. opengl 相关资料
  5. Android对话框dialog大全
  6. 工业以太网交换机故障的排障步骤
  7. linux命令之kill篇
  8. arailsdemo 1
  9. 计算机主板电源管理线路图,笔记本电源维修方法详解【图文教程】
  10. OCR文字识别方法综述
  11. 均线颜色怎么区分_股票均线颜色
  12. Win 10系统截图的7种方式【简单实用】
  13. GitLab CI/CD 基础教程(一)
  14. 《Xenogears》(异度装甲)隐含的原型与密码
  15. 树莓派linux控制录音,树莓派通过USB声卡录音和播放
  16. 云桌面虚拟化VDI、IDV、VOI三种主流架构的区别?
  17. 特征点检测(Landmark detection)
  18. python程序弹出输入框_Python弹出输入框并获取输入值的实例
  19. 关于QQ登录出现非官方应用 错误码100044的解决办法
  20. Canvas 绘制直线

热门文章

  1. 制作自己的Cydia发布源
  2. 区块链浏览器构建实战
  3. openshift operator 介绍
  4. 设计模式-一些输出方式demo
  5. 免费云服务器获取方法 云服务器购买
  6. vscode插件 中文一键转英文并生成多种命名格式 提效神器
  7. 【什么是DOM和BOM】
  8. 北京智源人工智能研究院(BAAI)前沿报告——强化学习领域
  9. gst-launch的-v参数
  10. uni-app引用第三方插件(根据银行卡卡号查询银行类型和卡类型)