首页 > 其他 > 详细

简单易懂的程序语言入门小册子(1):基于文本替换的解释器,lambda演算

时间:2014-04-17 18:25:35      阅读:675      评论:0      收藏:0      [点我收藏+]

最近比较闲,打算整理一下之前学习的关于程序语言的知识。主要的内容其实就是一边设计程序语言一边写解释器实现它。这些知识基本上来自Programming Languages and Lambda Calculi和Essentials of Programming Languages这两本书。

我还记得高中奥数竞赛培训时的老师这样说过:“解题时一定要抓住定义。” 编程和解题一样,也要抓住定义。 所以在写解释器前,得先定义好这门要解释的程序语言。 这门程序语言基于Lambda演算。

λbubuko.com,布布扣 演算讲起

真不想讲λbubuko.com,布布扣 演算……算了,还是简要说明一下。λbubuko.com,布布扣 演算之于程序语言中的地位好比集合论之于数学。正如每一本数学教材,都要从集合论开始; 每一本程序语言教材,也要从λbubuko.com,布布扣 演算讲起。 不过话说回来,追根溯源λbubuko.com,布布扣 演算也是从集合论搭起来。 咱就不走那么远了,又累又没什么意思……

λbubuko.com,布布扣 演算中的基本类型只有变量和函数两种。 变量用大写字母Xbubuko.com,布布扣 表示。 像a,b,x,y,abc,...bubuko.com,布布扣 都是变量。 一个函数包含两个元素: 一个是函数参数(形参),它是一个变量; 另一个元素是函数体,它是一个λbubuko.com,布布扣 演算表达式(这里是递归定义)。 用(lambda X M)表示一个函数, 其中X是一个变量,M是一个λbubuko.com,布布扣 演算表达式( 别吐槽参数X那里少了个括号。 )。 为了描述的简洁,也用λX.Mbubuko.com,布布扣 表示一个函数。

举个例子,λx.xbubuko.com,布布扣 是一个恒等函数f(x)=xbubuko.com,布布扣 。 在数学上一般用f(a)bubuko.com,布布扣 表示函数调用,abubuko.com,布布扣 是实参。 在λbubuko.com,布布扣 演算中把函数也放入括号,记为(λx.xa)bubuko.com,布布扣 。 函数调用的计算方法是在函数体中用实参替换形参。 在这个例子里(λx.xa)=abubuko.com,布布扣 。 这个计算过程称为归约。

λbubuko.com,布布扣 演算的函数都只包含一个参数。 如果要使用多参函数,可以用多个函数嵌套。 下面是一个例子:

λx.λy.(xy)bubuko.com,布布扣
这种技巧被称作currying。

从上面的讨论看出,λbubuko.com,布布扣 演算只包含三种表达式。 形式化地定义λbubuko.com,布布扣 演算的语法如下:

  M,N,Lbubuko.com,布布扣          bubuko.com,布布扣          bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣|bubuko.com,布布扣|bubuko.com,布布扣bubuko.com,布布扣Xbubuko.com,布布扣λX.Mbubuko.com,布布扣(MN)bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣
这里用大写字母Mbubuko.com,布布扣 Nbubuko.com,布布扣 Lbubuko.com,布布扣 代表λbubuko.com,布布扣 演算的表达式, 这是个递归定义,第二行、第三行出现了Mbubuko.com,布布扣 Nbubuko.com,布布扣 。 第三行表达式是一个函数调用,一般要求处于函数位置的Mbubuko.com,布布扣 应该要能归约成一个函数,否则归约就没法进行下去啦。

下面给出几个λbubuko.com,布布扣 演算的表达式的例子:

  bubuko.com,布布扣  bubuko.com,布布扣  bubuko.com,布布扣  bubuko.com,布布扣  bubuko.com,布布扣bubuko.com,布布扣xbubuko.com,布布扣λx.xbubuko.com,布布扣(λx.xy)bubuko.com,布布扣(λx.(xx)λx.x)bubuko.com,布布扣(λx.(xx)λx.(xx))bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

λbubuko.com,布布扣 演算的归约依赖于替换操作。 在介绍替换操作之前还得先介绍自由变量。

自由变量

考察一个表达式:(λx.(λx.xx)a)bubuko.com,布布扣 。 这个表达式归约到(λx.xa)bubuko.com,布布扣 。 可以看到,在(λx.(λx.xx))bubuko.com,布布扣 函数体(λx.xx)bubuko.com,布布扣 中参数位置的变量xbubuko.com,布布扣 λx.xbubuko.com,布布扣 中点后面的xbubuko.com,布布扣 是不一样的。 参数位置中的xbubuko.com,布布扣 被替换成abubuko.com,布布扣 ,而λx.xbubuko.com,布布扣 中点后面的xbubuko.com,布布扣 没有被替换。 被替换的xbubuko.com,布布扣 称为表达式(λx.xx)bubuko.com,布布扣 的自由变量。 在函数调用的替换过程中只有自由变量会被替换。

自由变量指一个表达式中没有受到约束的变量。 约束指这个变量不是作为某个函数的参数而存在。 如表达式λx.(fx)bubuko.com,布布扣 fbubuko.com,布布扣 是自由变量,xbubuko.com,布布扣 不是自由变量。 用FV(M)bubuko.com,布布扣 表示表达式Mbubuko.com,布布扣 中的所有自由变量的集合。

从这里开始,描述和λbubuko.com,布布扣 演算有关的一些定义和算法将遵循λbubuko.com,布布扣 演算的语法定义。 所以计算FV(M)bubuko.com,布布扣 的算法(也是FV(M)bubuko.com,布布扣 的精确定义)应该分成变量、函数和函数调用三种情况讨论:

  FV(X)bubuko.com,布布扣  FV(λX.M)bubuko.com,布布扣  FV((MN))bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣{X}bubuko.com,布布扣FV(M)?{X}bubuko.com,布布扣FV(M)FV(N)bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

替换

用记号M[XN]bubuko.com,布布扣 表示在表达式Mbubuko.com,布布扣 中将自由变量Xbubuko.com,布布扣 (如果有出现这个自由变量)替换成表达式Nbubuko.com,布布扣 。 更准确的定义如以下公式:

  Xbubuko.com,布布扣1bubuko.com,布布扣[Xbubuko.com,布布扣1bubuko.com,布布扣N]bubuko.com,布布扣  Xbubuko.com,布布扣2bubuko.com,布布扣[Xbubuko.com,布布扣1bubuko.com,布布扣N]bubuko.com,布布扣  bubuko.com,布布扣  (λXbubuko.com,布布扣1bubuko.com,布布扣.M)[Xbubuko.com,布布扣1bubuko.com,布布扣N]bubuko.com,布布扣  (λXbubuko.com,布布扣1bubuko.com,布布扣.M)[Xbubuko.com,布布扣2bubuko.com,布布扣N]bubuko.com,布布扣  bubuko.com,布布扣  (Mbubuko.com,布布扣1bubuko.com,布布扣Mbubuko.com,布布扣2bubuko.com,布布扣)[XN]bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣=bubuko.com,布布扣bubuko.com,布布扣Nbubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣bubuko.com,布布扣Xbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣bubuko.com,布布扣(λXbubuko.com,布布扣1bubuko.com,布布扣.M)bubuko.com,布布扣(λXbubuko.com,布布扣3bubuko.com,布布扣.M[Xbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣3bubuko.com,布布扣][Xbubuko.com,布布扣2bubuko.com,布布扣N])bubuko.com,布布扣Xbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣,Xbubuko.com,布布扣3bubuko.com,布布扣?FV(N),Xbubuko.com,布布扣3bubuko.com,布布扣?FV(M)?{Xbubuko.com,布布扣1bubuko.com,布布扣}bubuko.com,布布扣(Mbubuko.com,布布扣1bubuko.com,布布扣[XN]Mbubuko.com,布布扣2bubuko.com,布布扣[XN])bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣
第四个公式看着比较复杂,其实是为了避免Nbubuko.com,布布扣 中有自由变量Xbubuko.com,布布扣1bubuko.com,布布扣bubuko.com,布布扣 这种情况。 举个例子,λx.y[y(xx)]bubuko.com,布布扣 应该替换为λz.(xx)bubuko.com,布布扣 。 如果替换成λx.(xx)bubuko.com,布布扣 就不对了。

如果Nbubuko.com,布布扣 中没有自由变量Xbubuko.com,布布扣1bubuko.com,布布扣bubuko.com,布布扣 ,那么这个公式可以简化成:

  (λXbubuko.com,布布扣1bubuko.com,布布扣.M)[Xbubuko.com,布布扣2bubuko.com,布布扣N]=(λXbubuko.com,布布扣1bubuko.com,布布扣.M[Xbubuko.com,布布扣2bubuko.com,布布扣N])bubuko.com,布布扣bubuko.com,布布扣bubuko.com,布布扣

归约

所谓归约,可以理解成求值,或者表达式化简(初中好像有学过代数表达式化简)。 λbubuko.com,布布扣 演算有三种归约方法。 三种归约分别称为αbubuko.com,布布扣 归约,βbubuko.com,布布扣 归约和ηbubuko.com,布布扣 归约。 名字看着很渗人,不表示这三种归约难以理解,只说明命名的人没有一颗爱玩的心。

  •  αbubuko.com,布布扣 归约的意思是,函数参数变量的变量名是什么无关紧要。 比如λx.xbubuko.com,布布扣 λy.ybubuko.com,布布扣 表示的同一个函数。 这个归约很基本,但是几乎上不会被用到就是的了。
    λXbubuko.com,布布扣1bubuko.com,布布扣.Mbubuko.com,布布扣αbubuko.com,布布扣λXbubuko.com,布布扣2bubuko.com,布布扣.M[Xbubuko.com,布布扣1bubuko.com,布布扣Xbubuko.com,布布扣2bubuko.com,布布扣]bubuko.com,布布扣
  • βbubuko.com,布布扣 归约表示了函数调用过程,是最常用的归约。 βbubuko.com,布布扣 归约用函数调用的输入参数(实参)替换函数体中出现的参数变量(形参):
    (λX.MN)bubuko.com,布布扣βbubuko.com,布布扣M[XN]bubuko.com,布布扣
  • ηbubuko.com,布布扣 归约指:
    λx.(fx)bubuko.com,布布扣ηbubuko.com,布布扣fbubuko.com,布布扣
    这个有点怪,但仔细想想不难理解。

一个解释器的作用是输入一个表达式,输出该表达式归约到最简(不能再βbubuko.com,布布扣 归约)的形式。 一般我们是希望这个最简形式能够是一个变量(Xbubuko.com,布布扣 )或者一个函数(λX.Mbubuko.com,布布扣 ),因为函数调用是用来让人进行βbubuko.com,布布扣 归约的。 变量,或者函数,被称为“值”。 但是也有些坏掉了的表达式像(xx)bubuko.com,布布扣 ,由于xbubuko.com,布布扣 是个变量而非函数,这个表达式没法再归约。 通常这种表达式被认为非法的表达式。 如果输出这种结果就表示输入程序有误,程序崩溃。 另外有些表达式不能归约到某种最简形式,也就是无限循环(可怜的西西弗斯)。 无限循环的一个经典例子是这个输入:(λx.(xx)λx.(xx))bubuko.com,布布扣

一个解释器,给它一个输入,它会有以下三种情况:

  • 输出一个值:-)
  • 崩溃XD
  • 无限循环@_@

呼!总算写完。

简单易懂的程序语言入门小册子(1):基于文本替换的解释器,lambda演算,布布扣,bubuko.com

简单易懂的程序语言入门小册子(1):基于文本替换的解释器,lambda演算

原文:http://www.cnblogs.com/skabyy/p/3670193.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!