你好,類型(二):Lambda calculus

1. 匿名函數

現在很多種編程語言都支持匿名函數了,

例如,C# 3.0,C++ 11和Java 8中的lambda表達式,

又例如,Python 2.2.2中的lambda,ECMAScript 3的匿名函數,

ECMAScript 2015的箭頭函數(arrow function)等等。

更不論,Haskell,Lisp,Standard ML,這些函數式編程語言了。

越來越多的語言擁抱匿名函數,是因為在很多場景中,我們無需給函數事先指定一個名字,

並且結合詞法作用域和高階函數,會使某些問題用更直觀的方式得以解決。

從理論上來講,匿名函數具有和一般函數同樣的計算能力,

使用某些技術手段,可以讓匿名函數支持遞歸運算,從而完成任何圖靈可計算的任務。

然而,要想理解這一切,我們首先還得靜下心來,從基礎的 lambda 演算開始吧。

2. 自然數

lambda 演算聽起來是一個高大上的概念,實際上它只是一套「符號推導系統」。

人們首先定義某些合法的符號,然後再定義一些符號推導規則

最後就可以計算了,從一堆合法的符號得到另一堆,

這種推導過程稱之為「演算」。

為了讓 lambda 演算更容易被接受,我們暫時先岔開話題,看看自然數是怎麼定義的。

2.1 Peano系統

1889年,皮亞諾(Peano)為了給出自然數的集合論定義,

他建立了一個包含5條公設的公理系統,後人稱之為Peano系統

Peano系統是滿足以下公設的有序三元組 (M,F,e)

其中 M 為一個集合, FMM 的函數, e 為首元素,

(1) ein M

(2) MF 下是封閉的

(3) e 不在 F 的值域中

(4) F 是單射

(5)如果 M 的子集 A 滿足, ein A ,且 AF 下封閉,則 A=M

2.2 後繼

A 為一個集合,我們稱 Acup{A}A後繼,記作 A^+

求集合後繼的操作,稱為後繼運算

例如,

varnothing^+=varnothingcup{varnothing}={varnothing}

varnothing^{++}=varnothing^+cup{varnothing^+}={varnothing}cup{{varnothing}}={varnothing,{varnothing}}

varnothing^{+++}={varnothing,{varnothing},{varnothing,{varnothing}}}

2.3 歸納集

A 為一個集合,若 A 滿足,

(1) varnothingin A

(2) forall ain Aa^+in A

則稱 A歸納集

例如, {varnothing,varnothing^+,varnothing^{++},cdots} 是一個歸納集。

從歸納集的定義可知, varnothing,varnothing^+,varnothing^{++},cdots 是所有歸納集的元素,

於是,可以將它們定義為自然數,自然數集記為 N

sigma:N
ightarrow N ,滿足 sigma(n)=n^+ ,則稱 sigma後繼函數

則可以證明 (N,sigma,varnothing) 是一個Peano系統。

3. λ演算

λ演算,是1930年由邱奇(Alonzo Church)發明的一套形式系統,

它是從具體的函數定義,函數調用和函數複合中,抽象出來的數學概念。

3.1 語法

形式上, lambda 演算由3種語法項(term)組成,

(1)一個變數 x 本身,是一個合法的 lambda 項,

(2) lambda x.t_1 ,是一個合法的 lambda 項,稱為從項 t_1 中抽象出 x

(3) t_1 t_2 ,是一個合法的 lambda 項,稱為將 t_1 應用於 t_2

例如, (lambda x.(xy))(x (lambda x.(lambda x.x)))((lambda y.y)(lambda x.(xy))) ,都是合法的 lambda 項。

為了簡化描述,我們通常會省略一些括弧,以上三個 lambda 項可以寫成,

lambda x.xyx (lambda x.lambda x.x)(lambda y.y)(lambda x.xy)

對於形如 lambda x.t_1lambda 項來說,「 . 」後面會向右包含盡量多的內容。

現在我們有了一堆合法的字元串了。

可是,在給定推導規則之前,這些字元串之間都是沒有關聯的。

而且,我們也還沒有為這些符號指定語義,它們到底代表什麼也是不清楚的。

很顯然給這些符號指定不同的推導規則,會得到不同的公理系統

在眾多 lambda 演算系統中,最簡單的是 lambda_eta 系統,它指定了 alphaeta 兩種變換。

3.2 α變換

lambdaP 中包含了 lambda x.M

則我們可以把 M 中所有自由出現x ,全都換成 y ,即 lambda y.[y/x]M

這種更名變換,稱為 alpha 變換

其中,「自由出現」指的是 x 不被其他 lambda 抽象所綁定,

例如, lambda x.xy 中, y 是自由的,

x 就不是自由的,因為它被 lambda x. 綁定了。

如果 P 可以經過有限步 alpha 變換轉換為 Q ,就寫為 Pequiv_alpha Q

例如,

lambda xy.x(xy)=lambda x.(lambda y.x(xy))

equiv_alphalambda x.(lambda v.x(xv))

equiv_alphalambda u.(lambda v.u(uv))

=lambda uv.u(uv)

3.3 β變換

形如 (lambda x.M)Nlambda 項,可以經由eta 變換轉換為 [N/x]M

指的是,把 M 中所有自由出現的 x 都換成 N

如果 P 可以經過有限步 eta 變換轉換為 Q ,就寫為 P	riangleright_eta Q

例如,

(lambda x.x(xy))N	riangleright_eta N(Ny) (lambda x.xx)(lambda x.xx)	riangleright_eta [(lambda x.xx)/x](xx)=(lambda x.xx)(lambda x.xx)	riangleright_etacdots

我們發現,某些 lambda 項,可以無限進行 eta 變換。

而那些最終會終止的 eta 變換的結果,稱為 eta 範式eta normal form)。

3.4 邱奇編碼

現在我們有 lambda_eta 公理系統了,就可以依照 alphaeta 變換,對任意合法的 lambda 項進行變換。

假設我們有一個 lambda 項, lambda f.lambda x.x

還有另外一個 lambda 項, lambda n.lambda f.lambda x.f(nfx) ,記為 succ

我們來計算, succ(lambda f.lambda x.x)

可得, (lambda n.lambda f.lambda x.f(nfx))(lambda f.lambda x.x)	riangleright_etalambda f.lambda x.fx

我們再運用一次 succsucc(lambda f.lambda x.fx)	riangleright_etalambda f.lambda x.f(fx)

我們發現每次應用 succ ,都會給 lambda f.lambda x.x 中加一個 f

最終我們可以得到以下這些 lambda 項,

lambda f.lambda x.x

lambda f.lambda x.fx

lambda f.lambda x.f(fx)

lambda f.lambda x.f(f(fx))

cdots

lambda f.lambda x.f^nx

如果我們記 lambda f.lambda x.xequiv 0lambda f.lambda x.fxequiv 1cdotslambda f.lambda x.f^nxequiv n

我們就得到了自然數的另一種表示方式,稱之為邱奇編碼。

可以看到邱奇編碼與歸納集之間有異曲同工之妙。

3.5 語義

到目前為止,我們並未談及 lambda 項到底表示什麼含義

雖然 lambda x.M 看起來像是函數定義, (lambda x.M)N 看起來像是函數調用。

我們謹慎的使用公理化方法,從什麼是合法的 lambda 項出發,

定義 lambda_eta 系統中的公理——合法的 lambda 項,

然後又指定了該系統中的推導規則—— alphaeta 變換,

最終得到了一個形式化的公理系統(公理+推導規則)。

後文中,我們將談及 lambda 項的語義,然後再逐漸給它加上類型。


參考

離散數學教程

Lambda-Calculus and Combinators,an Introduction

Lecture Notes on the Lambda Calculus


下一篇:你好,類型(三):Combinatory logic


推薦閱讀:

深度學習進修之旅
業力與大腦神經編碼記憶 腦可塑性-大腦皮層增大-記憶學習經歷固化 大腦重構 關鍵期MeCP2蛋白 中風大腦修復
深度報文檢測基礎之編解碼
讓人困擾的Python 2編碼

TAG:Lambda演算 | 公理系統 | 編碼 |