学习笔记:λ演算(lambda calculate)
索引链接至此博客 负暄琐话
这几篇是讲lambda演算的,博主翻译了国外文章,在此也向译者的劳动表示致敬!
找个时间静下心来,配合着《the root of lisp》以及《实用common lisp编程》学习下这种计算模型
good math, bad math之Lambda算子简介
另外还有《the root of lisp》的 Chinese Translation
笔记一:Lambda的三种表达式(对应索引:简介、算子1)------------------2012.12.24 01:01
1.函数定义
语法: lambda x."函数体"
表示定义了一个带参数x的函数,将x赋值后返回字符串"函数体"所代表的值,之所以要用字符串这个概念,是因为lambda calculate不仅仅能定义出代 数运算,它能表示的是更多的演算,所以需要从更抽象的层面来理解它
举个例子,对于下列表达式:
1.x + y
2.if(x == true) then do f(y)
3.p(x)-->q(y)
4.lambda y.(x+y)
有代数式,编程语言,逻辑命题,甚至还有lambda函数本身。但是对于lambda calculate来说都属于它能处理的范畴,都可以被视为一个字符串,只要对该字符串声明了参数, 使用函数时为该参数赋值,就能得到该字符串所代表的表达式或值,表达式的意义及其本身的值由人类意识来决定。
2.标识符引用(identifier reference)
“一个标识符引用就是一个名字。这个名字和包括这个引用的函数定义里的参数同名。”
原博客译者后来又说到,标识符其实就是变量。按我的理解,所谓的引用就是在进行 lambda calculate时写下某个变量的名字。
3.函数引用
就是为函数的参数赋值,然后这个函数就变成一个确定的表达式,语法: (lambda x."函数体")value
例:已知有函数lambda x.x+3 当通过函数引用为参数赋值时,这个函数就会返回一个 有现实意义的字符串。
对于这个函数的参数x,这里我们给它赋值为5,即(lambda x.x+3)5,那么通过这种演算过后,表达式"lambda x.x+3"就要被改写成新的表达式"5+3"。
简而言之,若有F(x) == "lambda x.x+3",当执行完x="5"时,可得F(5) == "5+3"。
另外顺便先提下,lambda函数本身也可以作为变量值,假设我们干了这么一件 事:x="lambda y.y*5",那么可得F(lambda y.y*5)=="lambda y.y*5+3",这个字符串刚好是一个新的lambda函数。
我一直用双引号括起一些东西,只是想提醒下读者要把不同领域的表达式等同地视为字符串,lambda calculate处理的就是这些具有数理逻辑意义的字符串。个人觉得,想要理解它,需要有比学微积分时更抽象的抽象。越抽象的东西,越能描述出不同事物的统一性。
笔记二:几个概念(对应索引:算子2)------------------2012.12.25 13:50
有界变量与自由变量
若表达式中存在这么一个变量,它的名字与该表达式的参数声明中所声明的参数名一样,则该变量称为该表达式的有界变量,否则称为自由变量。
例1:lambda x . plus x y 该表达式声明了一个参数x,所以函数体"plus x y"中x对于该表达式是一个有界变量,而变量plus与y则是自由变量。
例2:lambda y . (lambda x . plus x y) 变量y对于内嵌表达式lambda x . plus x y是一个自由变量,但对于整个表达式来说,它是一个有界变量
多参函数
定义这么一个函数f(x,y) = "plus x y"
到了lambda calculate中则应该这样写 lambda y.(lambda x.plus x y)
括弧内函数接收一个参数x,返回的是一个表达式"plus x y"
当括弧内参数x被传递了实参之后,整个表达式就变成 lambda y.plus x y
括弧外的函数接收一个参数y
当它的参数y也被赋值以实参后,整个函数就返回表达式"plus x y"
这样,通过函数嵌套使得参数x,y都分别有一个函数进行处理,再加上传递实参后返回的表达式是"plus x y",
所以f(x,y) = "plus x y"与lambda y.(lambda x.plus x y)等价
后面译者又提到,为了方便表达
类似lambda y.(lambda x.plus x y)的多参数函数会被写成lambda x y.plus x y
Alpha转换
给已声明的参数改名,改名后与该参数对应的表达式内的有界变量也要跟着改名。这个与上面的“有界变量与自由变量”记得在离散数学的数理逻辑中也有提到。
Beta简化
其实就是前一笔记中提到的函数引用,就是一种在进行lambda演算时对表达式(或着说字符串)进行改写所依据的规则,还是用译者翻译过来的三个例子吧,嚼下别人吐出的甘蔗渣。
1.引用这么一个函数"lambda x . x + 1",我们给它的参数x赋值实参3,那么表达式的改写过程是这样"lambda x . x + 1"-------->"(lambda x . x + 1)3" -------> "3+1"
2. lambda y . (lambda x . x + y)q ------> lambda x, x+q 这个函数有一点特殊的意义。通过函数引用,从一个表达式产生了新的表达式,这个新的表达式会根据所传实参的不同而不同。到了编程语言里,这种特性的意义就是使得该语言能够将其自身代码作为它能处理的数据对象。也就是说,你能够用代码产生新代码!恩,我联想到了common lisp里面的宏,联想到了《the root of lisp》中仅用七个原始运算符就编写出了lisp的“编译器”的神奇一幕,这七个运算符构成了一个计算模型,实现了lisp语言本身,而这些运算符又属于lisp语言。
3.好,最后一堆甘蔗渣 ^_^|||
让我们来用Beta规则来简化这个"(lambda x y. x y) (lambda z . z * z) 3",我只给出过程哈
先还原为多参数函数的lambda calculate标准写法:((lambda x.(lambda y.xy))(lambda z.z*z))3
第一步。。。:"(lambda y.(lambda z.z*z)y)3"
第二步~ :"(lambda z.z*z)3"
最后一步!:"3*3"
搞定!继续复习期末考试去 O(∩_∩)O哈哈~
笔记三:毁了我有关数的世界观的“丘其数”(对应索引:算子3)------------------2013.01.19
18:14
Mark原文一段严格定义,我想通过这段mark就能说明看起来很简单的Alpha转化必须存在的原因:
我们用"free(x)"来代表表达式x里所有自由变量的集合。
lambda x . B e = B[x := e] if free(e) /subset free(B[x := e])
这个定义末尾的条件,"if free(e) /subset free(B[x:=e])"道出了我们需要Alpha转换的原因:仅当beta化简不会引起有界变量和自由变量的冲突时,我们可以实施Beta化简。如果一个变量“z”是"e"里的自由变量,那我们得保证beta化简不会让"z"变成有界变量。如果B里的有界变量和”e"里的自由变量重名,我们必须先用Alpha转换,使得重名的变量不再重名。形式化定义不够直观,直观描述又不够简洁。
Mark END
小标题不夸张,这部分真的有点毁世界观,有点像抽象代数。
lambda演算中,我们曾经认识的数其本质被赋予了新的意义——函数。数也是一种函数,称为丘其数,能被传递实参,返回函数值。自然数所对应的丘其数的定义如下
0: lambda s z.z
1: lambda s z.s z
2: lambda s z.s (s z)
3: lambda s z.s(s(s z))
......
n: lambda s z.s(s(....(s(s(s(s z)))....)) 这里有n个s,n-1对括弧
定义一个函数add,即加法运算:lambda xy.(lambda sz.(x s(y s z)))
我们用它来计算2+3。即为x传递实参lambda s2 z2.s2(s2 z2),为y传递实参 lambda s3 z3.s3(s3(s3 z3))
那么2+3 ==
1) lambda x y.lambda s z.x s(y s z) lambda s2 z2.s2(s2 z2) lambda s3 z3.s3(s3(s3 z3))
2) lambda s z.(lambda s2 z2.s2(s2 z2) s (lambda s3 z3.s3(s3(s3 z3)) s z))
3) lambda s z.lambda s2 z2.s2(s2 z2) s (s(s(s z)))