lambda演算入门

介绍如何进行简单lambda演算的计算(规约):形如下面这样的题目:

intro

https://www.jianshu.com/p/ebae04e1e47c 这一篇很清晰,基本涵盖了本文的内容。

可跳过本节,基本对做题没帮助

关键字

小写单字符用以命名参数,也叫变量(数学含义的)。

外加四个符号'(',')','.','λ'。

由它们组成符号串叫λ表达式,核心λ演算表达式是非常冗长的(见下文).为了清晰和简炼,再加上一类符号:

大写单字符、 特殊字符(如+、-、*、/)、大小写组成的标识符代替一个λ表达式。

EBNF语法

<λ-表达式> :: = <变量>

​ | λ<变量>.<λ-表达式>

​ | (<λ-表达式><λ-表达式>)

​ | (<λ-表达式>)

​ <变量> :: =<字母>

表达式的四种形式分别对应:(表达式也称公式,)[1]

  1. 标识符引用(Identifier reference):标识符引用就是一个名字(实参),这个名字用于匹配函数表达式中的某个参数名。
  2. 函数定义:Lambda演算中的函数是一个表达式,写成:lambda x . body,表示“一个参数(形参)为x的函数,它的返回值为body的计算结果。” 这时我们说:Lambda表达式绑定了参数x
  3. 函数应用(Function application):函数应用写成把函数值放到名字前面的形式,如(lambda x . plus x x) y
  4. 加括号仍是表达式

变量

作为变量的标识符可以代表参数或名字。

闭包(closure)或者叫完全绑定(complete binding)。在对一个Lambda演算表达式进行求值的时候,不能引用任何未绑定的标识符。如果一个标识符是一个闭合Lambda表达式的参数,我们则称这个标识符是(被)绑定的;如果一个标识符在任何封闭上下文中都没有绑定,那么它被称为自由变量。

函数

函数是头等程序对象(函数是值),可作为函数的输入输出。

缩写与变形

  • 用λ演算表示计算首先要表示域,由于λ演算系统的值也是公式,则每个域中先定义最基本几个公式,其它值通过演算实现。这样,表示计算的问题全集中在λ演算上了。由于λ演算中一切语义概念均用λ表达式表达。为了清晰采用命名替换使之更易读。

      T = λx.λy.x          //逻辑真值
    
         F = λx.λy.y          //逻辑假值
    
         1 = λx.λy.x y         //数1
    
         2 = λx.λy.x(x y)       //数2
    
     	n=λx.λy.x(x(…(x y)…)//n个x
         zerop = λn.n(λx.F)T      //判零函数
         + = add = λx.λy.λa.λb.((x a)(y a)b)
    

    zerop中的F、T可以用λ表达式展开,其它用法同。

  • 库里化:将两个参数的函数变为两个单参数函数:写只有一个参数的函数,而这个函数返回一个带一个参数的函数。

    库里化的原因是 核心的λ演算只有单目运算,例如:add 1它返回的结果是函数,再应用到后面的表达式上。这样,3+4就写add 3 4,add 3返回“加3函数”应用到4上当然就是7。写全了是:

    (λx.λy.λa.λb.((x a)(y a) b ))(λp.λq.(p p(p q)))(λs.λt.(s s s(s t)))
              =λa.λb.(a(a(a(a(a(a(a b)))))))
    

​ λa.λb.λc.λz.E = λabcz.E

​ = λ(abcz).E

​ = λ(a,b,c,z).E

​ = λa.(λb.(λc.(λz.E)))//库里化,因为语法中lambda后只有一个 变量

  • 命名 以大写单字符或标识符命名其λ表达式:

​ G = (λx.(y(yx)))

​ ((λx.(y(yx)))(λx.(y(yx)))) = (G G) = H

规约

Lambda演算(规约)只有两条真正的法则:称为Alpha和Beta。Alpha也被称为「转换」,Beta也被称为「规约」。λ函数的语义是它应用到变元上所实现的数学函数计算。从符号演算的角度应用就是符号表达式的归约(reduction),归约将复杂的表达式化成简单形式,即按一定的规则对符号表达式进行置换。

法则

(1) β归约,β归约的表达式是一个λ应用表达式(λx.M N),其左边子表达式是λ函数表达式,右边是任意λ表达式。β归约以右边的λ表达式置换函数体M中λ指明的那个形参变量。形式地,我们用[N/x,M]表示对(λx.M N)的置换。

先看一例,相互归约的符号标以下横线。

例11-4 归约数1的后继

(succ 1) => (λn. (λx.λy.n x(x y))1) //写出succ的λ表达式

​ => (λx.λy.(1 x(x y)))

​ => (λx.λy.((λp.λq.p q) x(x y))) //写出1的λ表达式

​ => (λx.λy.((λq. x q)(x y))

​ => (λx.λy.x(x y))=2 //按定义

(2) α 换名 归约中如发生改变束定性质,则允许换名(λ后跟的变量名),以保证原有束定关系。例如:

​ (λx. (λy.x)) (z y) //(z y)中y是自由变量

​ => λy.(z y) //此时(z y)中y被束定了,错误!

​ => (λx.(λw.x))(z y) //因(λy.x)中函数体无y,可换名

​ => λw.(z y) // 正确!

(3) η 归约 是消除一层约束的归约,形如λx.F x的表达式若x在F中不自由出现,则:

λx.F x => F

它的逆是任何一个F都可以加一套λx( )x,只要x在F中不自由出现。

显然,λx.f(x) => f 是β归约的特例。

优先级 【难点】

注意规约中的优先级比较混乱,其实按照λ演算的运算规则,谁先归约最后归约其结果是一样的。(Church-Rosser定理)每次归约只要找到可归约的子公式(λ应用表达式,即一个是λ函数表达式,一个是变元)即可归约,λ演算没有规定顺序。

比如

	λx.λy.x y a b 

=  λx.(λy.x y) a b //库里化的定义

=(λy.a y) b //合并前三项
=a b//去掉括号,括号可以任意添加,然后合并前三项

空格是可以无视的,主要看括号。那些基本范式的参数后面的body是默认加括号的,比如zerop = λn.n(λx.F)T 其实应该是λn.(n(λx.F)T)

其实括号也是随意的 以下表达式有相同的语义:

(fa),f(a),(f)a,(f)(a),((f)(a))

比如

λa.λb.((1 a) (1 a) b)
= λa.λb.((1 a) 1 a b )
= λa.λb.((1 a) λx. λy. x y a b)
= λa.λb.((1 a) (a b))
= λa.λb.(( λx. λy. x y a) (a b))
= λa.λb.( λx. λy. x y a (a b))//去括号
= 2

不过2的范式里确实是有括号的,这一点很迷

规约的语义

对应用表达式符号归约时,当施行(除α规则外)所有变换规则后没有新形式出现,则这种λ表达式叫范式。(并非所有λ表达式均可归约为范式。前述(λx.x x)(λx.x x)为不可归约的。)范式即λ演算的语义解释,归约后形如λx.F它就是函数,形如x x,(y (λx.z))就只能解释为数据了,只可以把它放在另一个应用中作变元进一步归约。

一些规则

有以下规则:

[1]若x不在M中自由出现,结果为M;

[2]若M = x,结果为N;

[3]若M = λy.k, x≠y,y不在N中自由出现,结果为λy.[N/x,k];

[4]若M = λy.k, x≠y,y在N中自由出现,结果为λz.[N/x,[z/y,k]],z≠x≠y且不在M,N


  1. 我的最爱Lambda演算——开篇 · cgnail's weblog ↩︎

posted @ 2021-12-22 19:55  SuuTTT  阅读(843)  评论(0编辑  收藏  举报