跳至內容

邱奇數

維基百科,自由的百科全書

邱奇編碼是把數據和運算符嵌入到lambda演算內的一種方式,最常見的形式即邱奇數,它使用lambda符號表示自然數。方法得名於阿隆佐·邱奇,他首先以這種方法把數據編碼到lambda演算中。

透過邱奇編碼,在其他符號系統中通常被認定為基本的項(比如整數、布爾值、有序對、列表和tagged unions)都會被映射到高階函數。在無型別lambda演算,函數是唯一的原始型別

邱奇編碼本身並非用來實踐原始型別,而是透過它來展現我們不須額外原始型別即可表達計算。

很多學數學的學生熟悉可計算函數集合的哥德爾編號;邱奇編碼是定義在lambda抽象而不是自然數上的等價運算。

用途

[編輯]

直接實現邱奇編碼會將某些訪問操作的時間複雜度從降低到(其中是資料結構的大小),這使得該編碼方式在實際應用中受到限制。[1]研究表明可以通過針對性優化解決這個問題,但大多數函數式編程語言選擇擴展其中間表示以包含代數數據類型[2] 儘管如此,邱奇編碼仍常用於理論論證,因為它在部分求值定理證明中具有自然表示優勢。[1]通過使用高階類型可以對操作進行類型標註,[3]並能便捷地實現原始遞歸[1]由於函數被假定為唯一的原始數據類型,這種設定簡化了許多證明過程。

邱奇編碼具有表示完整性但僅限於表徵層面。需要額外函數將這種表示轉換為通用數據類型以供人工解讀。由於邱奇定理等價性不可判定,通常無法判斷兩個函數是否具有外延等價性。轉換過程可能需要通過某種方式應用函數來提取其表徵值,或者以λ項字面量的形式查找其值。λ演算通常被解釋為使用內涵等價性。由於等價性的內涵定義與外延定義存在差異,在結果解釋方面可能存在潛在問題

邱奇數

[編輯]

邱奇數為使用邱奇編碼的自然數表示法,而用以表示自然數高階函數是個任意函數映射到它自身的n函數複合之函數,簡言之,數的「值」即等價於參數被函數包裹的次數。

不論邱奇數為何,其都是接受兩個參數的函數。邱奇數012、... 在λ演算中的定義如下:

0 不應用函數開始, 1 應用函數一次, 2 應用函數兩次, 3 應用函數三次,依此類推

邱奇數3表示對任意給定函數應用三次的操作。當輸入函數被提供時,首先應用於初始參數,然後連續應用於自身結果。最終結果並非數字3(除非初始參數恰好為0且函數為後繼函數)。邱奇數3的本質是函數的應用次數,而非計算結果本身。其核心意義在於「重複三次」的動作,這正是「三次」概念的直觀體現

就是說,自然數被表示為邱奇數n,它對於任何lambda-項FX有著性質:

n F X =β Fn X

使用邱奇數的計算

[編輯]

在 lambda 演算中,數值函數被表示為在邱奇數上的相應函數。這些函數在大多數函數式語言中可以通過 lambda 項的直接變換來實現(服從於類型約束)(請參閱將lambda表達式轉換為函數)。

加法函數 利用了恆等式

後繼函數 β-等價於(plus 1)。

乘法函數 利用了恆等式

指數函數 通過邱奇數定義給出:將定義中的代入可得,因此:

對應的lambda表達式為:

前驅函數 的實現較為複雜:

邱奇數通過n次應用函數來運作。前驅函數需要返回一個應用參數n-1次的函數。這通過構建包含fx的容器來實現,該容器以省略第一次函數應用的方式初始化(詳見前驅函數推導)。

基於前驅函數可定義減法函數:

邱奇數函數一表

[編輯]
函數 代數 等同 函數定義 Lambda 表達式
後繼 ...
加法
乘法
指數 [a]
前驅[b]

減法[b] ...

注意

  1. ^ 此公式是邱奇數 n 的定義,其中
  2. ^ 2.0 2.1 在邱奇編碼中,

前驅函數推導

[編輯]

邱奇編碼中使用的前驅函數定義為:

為了減少一次函數應用次數來構造前驅函數,需採用容器函數封裝值。定義新函數 incinit 替代原函數f和參數x,其中容器函數稱為value。下表左側展示了邱奇數n作用於incinit的情況:

通用遞歸規則為:

若定義從容器中提取值的函數extract

則可構造同數函數samenum

通過將init替換為特殊容器const(該容器首次調用時忽略參數以跳過第一次函數應用),可推導前驅函數:

具體函數定義如下:

最終得到前驅函數的lambda表達式:

值容器

[編輯]

值容器將函數作用於其內部值,定義為:

即:

Inc函數

[編輯]

inc 函數需接收包含v的容器,返回包含f v的新容器:

g為值容器:

則:

因此:

提取函數

[編輯]

通過應用恆等函數提取值:

利用I可得:

故:

Const容器

[編輯]

為實現pred函數,需將init替換為不應用fconst容器。該容器需滿足:

當滿足條件:

對應的lambda表達式為:

前驅函數的另一種解釋

[編輯]

使用組合子符號可簡化前驅函數的解釋:

通過下列推導可驗證其正確性:

通過eta-歸約和歸納法可得:

前驅函數的另一種定義

[編輯]

使用序對可定義前驅函數:

此定義雖簡潔但展開式較複雜,以為例:

除法函式

[編輯]

自然數除法可通過以下方式實現:[4]

計算需要多次beta歸約。除非手動進行歸約,否則這並不重要,但最好避免重複計算。最簡單的數值檢測謂詞是IsZero,故考慮條件:

此條件等價於而非。若採用該條件,則上述數學定義可轉化為邱奇數函數:

此定義僅調用一次,但結果為此公式給出的是的值。

通過給n加1後調用divide可修正該問題,定義式為:

divide1為遞歸定義,需用Y組合子實現遞歸。通過以下步驟創建新函數div

  • 左側替換:
  • 右側替換:

得到:

完整定義式為:

其中:

最終展開式:

以文本格式表示(用\代替λ):

divide = (\n.((\f.(\x.x x) (\x.f (x x))) (\c.\n.\m.\f.\x.(\d.(\n.n (\x.(\a.\b.b)) (\a.\b.a)) d ((\f.\x.x) f x) (f (c d m f x))) ((\m.\n.n (\n.\f.\x.n (\g.\h.h (g f)) (\u.x) (\u.u)) m) n m))) ((\n.\f.\x. f (n f x)) n))

例如,9/3可表示為:

divide (\f.\x.f (f (f (f (f (f (f (f (f x))))))))) (\f.\x.f (f (f x)))

使用lambda演算計算器,按正規順序歸約後結果為3:

\f.\x.f (f (f (x)))

有符號數

[編輯]

通過使用包含正負值的邱奇序對,可將邱奇數擴展至有符號數[5]。整數值即兩個邱奇數的差值。

自然數轉有符號數的定義為:

取反操作通過交換序對元素實現:

當序對中某一元素為零時,整數表示更自然。OneZero函數確保該條件:

使用Y組合子實現遞歸:

加減運算

[編輯]

加法數學定義為:

對應lambda表達式:

減法定義為:

對應lambda表達式:

乘除運算

[編輯]

乘法定義為:

對應lambda表達式:

除法需確保序對元素含零(見上文的OneZero),定義輔助函數:

除法表達式:

有理數與實數

[編輯]

有理數可表示為有符號數序對,可計算實數可通過極限過程編碼[6][7]。複數可自然地表示為實數序對。上述數據類型驗證了邱奇-圖靈論題:任何數據類型或計算均可編碼於lambda演算中。

換成其它表達法

[編輯]

大部分真實世界的程式語言都提供原生於機器的整數,churchunchurch 函式會在整數及與之對應的邱奇數間轉換。這裡使用Haskell撰寫函式, \ 等同於lambda演算的 λ。 用其它語言表達也會很類似。

type Church a = (a -> a) -> a -> a

church :: Integer -> Church Integer
church 0 = \f -> \x -> x
church n = \f -> \x -> f (church (n-1) f x)

unchurch :: Church Integer -> Integer
unchurch cn = cn (+ 1) 0

邱奇布爾值

[編輯]

邱奇布爾值是布爾值的邱奇編碼形式。某些程式語言使用這個方式來實踐布爾算術的模型,SmalltalkPico即為典型示例。

布爾邏輯本質上是選擇機制。邱奇布爾值的編碼形式為接收兩個參數的函數:

  • (true)選擇第一個參數
  • (false)選擇第二個參數

其標準定義為:

這種編碼允許謂詞函數(返回邏輯值的函數)直接作為條件語句使用。當布爾函數作用於兩個參數時,將根據真值返回其中一個參數:

predicate-x為真則返回then-clause,否則返回else-clause

由於真值與假值的選擇特性,它們可組合出各類邏輯運算符。需注意邏輯非not存在多種實現方式:

註:

  • 1 求值策略使用應用次序時,這個方法才正確。
  • 2 求值策略使用正常次序時,這個方法才正確。

運算示例解析:

謂詞

[編輯]

謂詞是返回布爾值的函數。最基礎的謂詞是,當其參數為邱奇數時返回,否則返回

下列謂詞檢測第一個參數是否小於等於第二個參數:

基於恆等關係:

相等性檢測可定義為:

邱奇序對

[編輯]

邱奇序對是二元組的邱奇編碼實現。序對被表示為接收函數的函數,當傳入參數時會將該參數作用於序對的兩個分量。其lambda演算定義為:

示例推導:

列表編碼

[編輯]

不可變列表由列表節點構成,其基本操作包括:

函數 描述
nil 構造空列表
isnil 檢測列表是否為空
cons 在列表頭部添加元素
head 獲取列表首元素
tail 獲取列表尾部

以下給出四種不同的列表表示法:

  • 使用雙序對構造列表節點(支持空列表)
  • 使用單序對構造列表節點
  • 基於右摺疊函數的列表表示
  • 採用Scott編碼的模式匹配參數化表示

雙序對列表節點

[編輯]

非空列表可用邱奇序對表示:

  • First 存儲首元素
  • Second 存儲尾部

為支持空列表,需額外包裹序對形成三層結構:

  • First - 空列表標識符
  • Second.First 存儲首元素
  • Second.Second 存儲尾部

基於此的核心操作定義如下:[8]

表達式 描述
序對首元素為true表示空列表
提取空列表標識符
構造非空列表節點
通過second.first獲取首元素
通過second.second獲取尾部

注意:當列表為空時,head和tail函數不應被調用。

單序對列表節點

[編輯]

另一種定義方式[9]

通用處理模板定義為:

其他擴展操作:




右摺疊列表表示

[編輯]

作為邱奇序對編碼的替代方案,列表可通過其右摺疊函數進行編碼。例如,包含三個元素x、y、z的列表可編碼為高階函數,當該函數應用組合子c和初始值n時,返回c x (c y (c z n))。這等價於部分應用函數組合鏈的調用:(c x ∘ c y ∘ c z) n。

此列表表示可在系統F類型系統中定義。

與邱奇數的對應關係並非巧合,邱奇數本質上是單元值列表(如[() () ()])的一進制編碼,列表長度即表示自然數值。對此類列表進行右摺疊時,組合函數忽略元素值,其本質與邱奇數中的函數組合鏈(即(c () ∘ c () ∘ c ()) n = (f ∘ f ∘ f) n)具有等價性。

Scott編碼列表表示

[編輯]

另一種實現方式是採用Scott編碼,這種方式能生成更簡潔的代碼[10](參見摩根森-斯科特編碼)。

該編碼的核心思想是利用模式匹配的特性。以Scala語法為例,假設list表示包含空列表Nil和構造器Cons(h, t)的列表類型,可通過模式匹配進行計算:

list match {
  case Nil        => nilCode
  case Cons(h, t) => consCode(h,t)
}

列表的行為由其模式匹配決定,因此可將列表定義為接收nilCodeconsCode參數的函數:

n對應空列表處理參數,c對應非空列表處理參數,則: 空列表定義為:

非空列表(含首元素h和尾部t)定義為:

更一般地,包含種構造器的代數數據類型將被編碼為具有個參數的函數。當第個構造器包含個參數時,對應編碼參數也接收個參數。

該編碼可在無類型λ演算中使用,但帶類型版本需支持遞歸和類型多態的系統。以元素類型E、計算結果類型C的列表為例,其遞歸類型定義為("=>"表示函數類型):

type List =
  C =>                    // 空列表分支
  (E => List => C) =>     // 非空列表分支
  C                       // 模式匹配结果

支持任意計算類型的列表需量化類型C,而泛型列表還需將元素類型E作為類型參數。

參見

[編輯]

外部連結

[編輯]
  1. ^ 1.0 1.1 1.2 Trancón y Widemann, Baltasar; Parnas, David Lorge. Olaf Chitil; Zoltán Horváth; Viktória Zsók , 編. Implementation and Application of Functional Languages. 19th International Workshop, IFL 2007, Freiburg, Germany, September 27–29, 2007 Revised Selected Papers. Lecture Notes in Computer Science 5083: 228–229. 2008. ISBN 978-3-540-85372-5. doi:10.1007/978-3-540-85373-2_13. 
  2. ^ Jansen, Jan Martin; Koopman, Pieter W. M.; Plasmeijer, Marinus J. Efficient interpretation by transforming data types and patterns to functions. Nilsson, Henrik (編). Trends in functional programming. Volume 7. Bristol: Intellect. 2006: 73–90. CiteSeerX 10.1.1.73.9841可免費查閱. ISBN 978-1-84150-188-8. 
  3. ^ Predecessor and lists are not representable in simply typed lambda calculus. Lambda Calculus and Lambda Calculators. okmij.org. 
  4. ^ Allison, Lloyd. Lambda Calculus Integers. 
  5. ^ Bauer, Andrej. Andrej对问题的回答:"使用lambda演算表示负数和复数". 
  6. ^ 精确实数计算. Haskell. (原始內容存檔於2015-03-26). 
  7. ^ Bauer, Andrej. 实数计算软件. GitHub. 2022-09-26. 
  8. ^ Pierce, Benjamin C. 类型与程序语言. 麻省理工出版社. 2002: 500. ISBN 978-0-262-16209-8. 
  9. ^ 川普, 約翰. 14. 二元λ演算与组合逻辑. 卡魯德, 克里斯蒂安·S (編). 从莱布尼茨到柴廷的随机性与复杂性. 世界科學出版公司. 2007: 237–262. ISBN 978-981-4474-39-9. 
    PDF版本:川普, 約翰. 二元λ演算与组合逻辑 (PDF). 2014-05-14 [2017-11-24]. 
  10. ^ Jansen, Jan Martin. λ演算编程:从Church到Scott的往返. Achten, Peter; Koopman, Pieter W. M. (編). 函数式代码之美——献给里努斯·普拉斯梅尔的61岁诞辰. 計算機科學講義 8106. 施普林格. 2013: 168–180. ISBN 978-3-642-40354-5. doi:10.1007/978-3-642-40355-2_12.