module plfa.part2.More where

到此,我们主要集中于一门基于 Plotkin 的 PCF 的相对轻便的语言,包括了函数、自然数和不动点。 在本章中,我们将扩展我们的演算,来支持下列特性:

  • 原语数字
  • let 绑定
  • 积的替代表示方法
  • 单元类型
  • 单元类型的替代表示方法
  • 空类型
  • 列表

所有上述数据类型和本书第一部分描述的相近。 对于 let 和数据类型的「替代表示方法」,我们展示如何将它们翻译至演算中其他的构造。 介绍的大部分将由非形式化的方式展示。 我们展示如何形式化前四种构造,并将其余留给读者作为习题。

非形式化的表述会以类似于 Lambda 章节中的形式,使用外在类型的项给出。 而形式化的表述会以类似于 DeBruijn 章节中的形式,使用内在类型的项给出。

到现在,使用符号来解释应该可以比文字更简洁、更精确、更易于跟随。 对于每一种构造,我们给出它的语法、赋型、归约和例子。 在需要的时候,我们也会给出构造的翻译;在下个章节我们会正式地证明翻译的正确性。

原语数字

我们定义 Nat 类型,等同于内置的自然数类型,并定义乘法作为数字的基本运算:

语法

A, B, C ::= ...                     类型
  Nat                                 原语自然数

L, M, N ::= ...                     项
  con c                               常量
  L `* M                              乘法

V, W ::= ...                        值
  con c                               常量

赋型

con 规则的前提不同寻常,它指代了一个 Agda 的赋型判断,而不是 我们定义的演算中的赋型判断。

c : ℕ
--------------- con
Γ ⊢ con c : Nat

Γ ⊢ L : Nat
Γ ⊢ M : Nat
---------------- _`*_
Γ ⊢ L `* M : Nat

归约

直接定义原语的规则,例如下面的最后一条规则,被称为 δ 规则。 这里的 δ 规则使用 Agda 标准库中的自然数乘法来定义原语数字的乘法。

L —→ L′
----------------- ξ-*₁
L `* M —→ L′ `* M

M —→ M′
----------------- ξ-*₂
V `* M —→ V `* M′

----------------------------- δ-*
con c `* con d —→ con (c * d)

例子

下面是一个求立方的函数的例子:

cube : ∅ ⊢ Nat ⇒ Nat
cube = ƛ x ⇒ x `* x `* x

Let 绑定

Let 绑定只影响项的语法;不引入新的值或者类型:

语法

L, M, N ::= ...                     项
  `let x `= M `in N                   let

赋型

Γ ⊢ M ⦂ A
Γ , x ⦂ A ⊢ N ⦂ B
------------------------- `let
Γ ⊢ `let x `= M `in N ⦂ B

归约

M —→ M′
--------------------------------------- ξ-let
`let x `= M `in N —→ `let x `= M′ `in N

--------------------------------- β-let
`let x `= V `in N —→ N [ x := V ]

下面是一个求十次方的函数:

exp10 : ∅ ⊢ Nat ⇒ Nat
exp10 = ƛ x ⇒ `let x2  `= x  `* x  `in
              `let x4  `= x2 `* x2 `in
              `let x5  `= x4 `* x  `in
              x5 `* x5

翻译

我们可以将每个 let 项翻译成一个抽象:

(`let x `= M `in N) †  =  (ƛ x ⇒ (N †)) · (M †)

此处的 M † 代表了将项 M 从带有此构造的演算到不带此构造演算的翻译。

语法

A, B, C ::= ...                     类型
  A `× B                              积类型

L, M, N ::= ...                     项
  `⟨ M , N ⟩                          有序对
  `proj₁ L                            投影第一分量
  `proj₂ L                            投影第二分量

V, W ::= ...                        值
  `⟨ V , W ⟩                          有序对

赋型

Γ ⊢ M ⦂ A
Γ ⊢ N ⦂ B
----------------------- `⟨_,_⟩ 或 `×-I
Γ ⊢ `⟨ M , N ⟩ ⦂ A `× B

Γ ⊢ L ⦂ A `× B
---------------- `proj₁ 或 `×-E₁
Γ ⊢ `proj₁ L ⦂ A

Γ ⊢ L ⦂ A `× B
---------------- `proj₂ 或 `×-E₂
Γ ⊢ `proj₂ L ⦂ B

归约

M —→ M′
------------------------- ξ-⟨,⟩₁
`⟨ M , N ⟩ —→ `⟨ M′ , N ⟩

N —→ N′
------------------------- ξ-⟨,⟩₂
`⟨ V , N ⟩ —→ `⟨ V , N′ ⟩

L —→ L′
--------------------- ξ-proj₁
`proj₁ L —→ `proj₁ L′

L —→ L′
--------------------- ξ-proj₂
`proj₂ L —→ `proj₂ L′

---------------------- β-proj₁
`proj₁ `⟨ V , W ⟩ —→ V

---------------------- β-proj₂
`proj₂ `⟨ V , W ⟩ —→ W

例子

下面是一个交换有序对中分量的函数:

swap× : ∅ ⊢ A `× B ⇒ B `× A
swap× = ƛ z ⇒ `⟨ `proj₂ z , `proj₁ z ⟩

积的替代表示方法

与其使用两种消去积类型的方法,我们可以使用一个匹配表达式来同时绑定两个变量, 作为积的替代表示方法。 我们重复完整的语法,但只给出新的赋型和归约规则:

语法

A, B, C ::= ...                     类型
  A `× B                              积累性

L, M, N ::= ...                     项
  `⟨ M , N ⟩                          有序对
  case× L [⟨ x , y ⟩⇒ M ]             匹配

V, W ::=                            值
  `⟨ V , W ⟩                          有序对

赋型

Γ ⊢ L ⦂ A `× B
Γ , x ⦂ A , y ⦂ B ⊢ N ⦂ C
------------------------------- case× 或 ×-E
Γ ⊢ case× L [⟨ x , y ⟩⇒ N ] ⦂ C

归约

L —→ L′
--------------------------------------------------- ξ-case×
case× L [⟨ x , y ⟩⇒ N ] —→ case× L′ [⟨ x , y ⟩⇒ N ]

--------------------------------------------------------- β-case×
case× `⟨ V , W ⟩ [⟨ x , y ⟩⇒ N ] —→ N [ x := V ][ y := W ]

下面是用新记法重写的交换有序对中分量的函数:

swap×-case : ∅ ⊢ A `× B ⇒ B `× A
swap×-case = ƛ z ⇒ case× z
                     [⟨ x , y ⟩⇒ `⟨ y , x ⟩ ]

翻译

我们可以将替代表示方法翻译到用投影的表示方法:

  (case× L [⟨ x , y ⟩⇒ N ]) †
=
  `let z `= (L †) `in
  `let x `= `proj₁ z `in
  `let y `= `proj₂ z `in
  (N †)

这里 z 是一个不在 N 中以自由变量出现的变量。 我们将这样的变量叫做新鲜(Fresh)的变量。

可能有人认为我们可以使用下面更紧凑的翻译:

-- 错误
  (case× L [⟨ x , y ⟩⇒ N ]) †
=
  (N †) [ x := `proj₁ (L †) ] [ y := `proj₂ (L †) ]

但是这样的话它们表现的不一样。 第一项总是在归约 N 之前归约 L,它只计算 `proj₁`proj₂一次。 第二项在归约 N 之前不先将 L 归约至值,取决于 xyN 中出现的次数, 它将归约 L 很多次或者根本不归约,因此它会计算 `proj₁`proj₂ 很多次或者根本不计算。

我们也可以反向的翻译:

(`proj₁ L) ‡  =  case× (L ‡) [⟨ x , y ⟩⇒ x ]
(`proj₂ L) ‡  =  case× (L ‡) [⟨ x , y ⟩⇒ y ]

语法

A, B, C ::= ...                     类型
  A `⊎ B                              和类型

L, M, N ::= ...                     项
  `inj₁ M                             注入第一分量
  `inj₂ N                             注入第二分量
  case⊎ L [inj₁ x ⇒ M |inj₂ y ⇒ N ]   匹配

V, W ::= ...                        值
  `inj₁ V                             注入第一分量
  `inj₂ W                             注入第二分量

赋型

Γ ⊢ M ⦂ A
-------------------- `inj₁ 或 ⊎-I₁
Γ ⊢ `inj₁ M ⦂ A `⊎ B

Γ ⊢ N ⦂ B
-------------------- `inj₂ 或 ⊎-I₂
Γ ⊢ `inj₂ N ⦂ A `⊎ B

Γ ⊢ L ⦂ A `⊎ B
Γ , x ⦂ A ⊢ M ⦂ C
Γ , y ⦂ B ⊢ N ⦂ C
----------------------------------------- case⊎ 或 ⊎-E
Γ ⊢ case⊎ L [inj₁ x ⇒ M |inj₂ y ⇒ N ] ⦂ C

归约

M —→ M′
------------------- ξ-inj₁
`inj₁ M —→ `inj₁ M′

N —→ N′
------------------- ξ-inj₂
`inj₂ N —→ `inj₂ N′

L —→ L′
---------------------------------------------------------------------- ξ-case⊎
case⊎ L [inj₁ x ⇒ M |inj₂ y ⇒ N ] —→ case⊎ L′ [inj₁ x ⇒ M |inj₂ y ⇒ N ]

--------------------------------------------------------- β-inj₁
case⊎ (`inj₁ V) [inj₁ x ⇒ M |inj₂ y ⇒ N ] —→ M [ x := V ]

--------------------------------------------------------- β-inj₂
case⊎ (`inj₂ W) [inj₁ x ⇒ M |inj₂ y ⇒ N ] —→ N [ y := W ]

例子

下面是交换和的两个分量的函数:

swap⊎ : ∅ ⊢ A `⊎ B ⇒ B `⊎ A
swap⊎ = ƛ z ⇒ case⊎ z
                [inj₁ x ⇒ `inj₂ x
                |inj₂ y ⇒ `inj₁ y ]

单元类型

对于单元类型来说,有一种方法引入单元类型,但是没有消去单元类型的方法。 单元类型没有归约规则。

语法

A, B, C ::= ...                     类型
  `⊤                                  单元类型

L, M, N ::= ...                     项
  `tt                                 单元值

V, W ::= ...                        值
  `tt                                 单元值

赋型

------------ `tt 或 ⊤-I
Γ ⊢ `tt ⦂ `⊤

归约

(无)

例子

下面是 AA `× `⊤的同构:

to×⊤ : ∅ ⊢ A ⇒ A `× `⊤
to×⊤ = ƛ x ⇒ `⟨ x , `tt ⟩

from×⊤ : ∅ ⊢ A `× `⊤ ⇒ A
from×⊤ = ƛ z ⇒ `proj₁ z

单元类型的替代表达方法

与其没有消去单元类型的方法,我们可以使用一个匹配表达式来绑定零个变量, 作为单元类型的替代表示方法。 我们重复完整的语法,但只给出新的赋型和归约规则:

语法

A, B, C ::= ...                     类型
  `⊤                                  单元类型

L, M, N ::= ...                     项
  `tt                                 单元值
  `case⊤ L [tt⇒ N ]                   匹配

V, W ::= ...                        值
  `tt                                 单元值

赋型

Γ ⊢ L ⦂ `⊤
Γ ⊢ M ⦂ A
------------------------ case⊤ 或者 ⊤-E
Γ ⊢ case⊤ L [tt⇒ M ] ⦂ A

归约

L —→ L′
------------------------------------- ξ-case⊤
case⊤ L [tt⇒ M ] —→ case⊤ L′ [tt⇒ M ]

----------------------- β-case⊤
case⊤ `tt [tt⇒ M ] —→ M

下面是用新记法重新 AA ‵× `⊤ 的同构的一半:

from×⊤-case : ∅ ⊢ A `× `⊤ ⇒ A
from×⊤-case = ƛ z ⇒ case× z
                      [⟨ x , y ⟩⇒ case⊤ y
                                    [tt⇒ x ] ]

翻译

我们可以将替代表示方法翻译到用没有匹配式的表示方法:

(case⊤ L [tt⇒ M ]) †  =  `let z `= (L †) `in (M †)

此处 z 是一个在 M 中不以自由变量出现的变量。

空类型

对于空类型来说,只有一种消去此类型的值的方法,但是没有引入此类型的值的方法。 没有空类型的值,也没有归约规则,但是有 β 规则。 case⊥ 构造和 Agda 中的 ⊥-elim 的作用相似:

语法

A, B, C ::= ...                     类型
  `⊥                                  空类型

L, M, N ::= ...                     项
  case⊥ L []                          匹配

赋型

Γ ⊢ L ⦂ `⊥
------------------ case⊥ 或 ⊥-E
Γ ⊢ case⊥ L [] ⦂ A

归约

L —→ L′
------------------------- ξ-case⊥
case⊥ L [] —→ case⊥ L′ []

例子

下面是 AA `⊎ `⊥ 的同构:

to⊎⊥ : ∅ ⊢ A ⇒ A `⊎ `⊥
to⊎⊥ = ƛ x ⇒ `inj₁ x

from⊎⊥ : ∅ ⊢ A `⊎ `⊥ ⇒ A
from⊎⊥ = ƛ z ⇒ case⊎ z
                 [inj₁ x ⇒ x
                 |inj₂ y ⇒ case⊥ y
                             [] ]

列表

语法

A, B, C ::= ...                     类型
  `List A                             列表类型

L, M, N ::= ...                     项
  `[]                                 空列表
  M `∷ N                              构造列表
  caseL L [[]⇒ M | x ∷ y ⇒ N ]        匹配

V, W ::= ...                        值
  `[]                                 空列表
  V `∷ W                              构造列表

赋型

----------------- `[] 或 List-I₁
Γ ⊢ `[] ⦂ `List A

Γ ⊢ M ⦂ A
Γ ⊢ N ⦂ `List A
-------------------- _`∷_ 或 List-I₂
Γ ⊢ M `∷ N ⦂ `List A

Γ ⊢ L ⦂ `List A
Γ ⊢ M ⦂ B
Γ , x ⦂ A , xs ⦂ `List A ⊢ N ⦂ B
-------------------------------------- caseL 或 List-E
Γ ⊢ caseL L [[]⇒ M | x ∷ xs ⇒ N ] ⦂ B

归约

M —→ M′
----------------- ξ-∷₁
M `∷ N —→ M′ `∷ N

N —→ N′
----------------- ξ-∷₂
V `∷ N —→ V `∷ N′

L —→ L′
--------------------------------------------------------------- ξ-caseL
caseL L [[]⇒ M | x ∷ xs ⇒ N ] —→ caseL L′ [[]⇒ M | x ∷ xs ⇒ N ]

------------------------------------ β-[]
caseL `[] [[]⇒ M | x ∷ xs ⇒ N ] —→ M

--------------------------------------------------------------- β-∷
caseL (V `∷ W) [[]⇒ M | x ∷ xs ⇒ N ] —→ N [ x := V ][ xs := W ]

例子

下面是列表的映射函数:

mapL : ∅ ⊢ (A ⇒ B) ⇒ `List A ⇒ `List B
mapL = μ mL ⇒ ƛ f ⇒ ƛ xs ⇒
         caseL xs
           [[]⇒ `[]
           | x ∷ xs ⇒ f · x `∷ mL · f · xs ]

形式化

我们接下来展示如何形式化:

  • 原语数字
  • let 绑定
  • 积的替代表示方法

其余构造的形式化作为练习留给读者。

导入

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Empty using (; ⊥-elim)
open import Data.Nat using (; zero; suc; _*_; _<_; _≤?_; z≤n; s≤s)
open import Relation.Nullary using (¬_)
open import Relation.Nullary.Decidable using (True; toWitness)

语法

infix  4 _⊢_
infix  4 _∋_
infixl 5 _,_

infixr 7 _⇒_
infixr 9 _`×_

infix  5 ƛ_
infix  5 μ_
infixl 7 _·_
infixl 8 _`*_
infix  8 `suc_
infix  9 `_
infix  9 S_
infix  9 #_

类型

data Type : Set where
  `ℕ    : Type
  _⇒_   : Type  Type  Type
  Nat   : Type
  _`×_  : Type  Type  Type

语境

data Context : Set where
     : Context
  _,_ : Context  Type  Context

变量及查询判断

data _∋_ : Context  Type  Set where

  Z :  {Γ A}
      ---------
     Γ , A  A

  S_ :  {Γ A B}
     Γ  B
      ---------
     Γ , A  B

项以及赋型判断

data _⊢_ : Context  Type  Set where

  -- 变量

  `_ :  {Γ A}
     Γ  A
      -----
     Γ  A

  -- 函数

  ƛ_  :   {Γ A B}
     Γ , A  B
      ---------
     Γ  A  B

  _·_ :  {Γ A B}
     Γ  A  B
     Γ  A
      ---------
     Γ  B

  -- 自然数

  `zero :  {Γ}
      ------
     Γ  `ℕ

  `suc_ :  {Γ}
     Γ  `ℕ
      ------
     Γ  `ℕ

  case :  {Γ A}
     Γ  `ℕ
     Γ  A
     Γ , `ℕ  A
      -----
     Γ  A

  -- 不动点

  μ_ :  {Γ A}
     Γ , A  A
      ----------
     Γ  A

  -- 原语数字

  con :  {Γ}
     
      -------
     Γ  Nat

  _`*_ :  {Γ}
     Γ  Nat
     Γ  Nat
      -------
     Γ  Nat

  -- let

  `let :  {Γ A B}
     Γ  A
     Γ , A  B
      ----------
     Γ  B

  -- 积

  `⟨_,_⟩ :  {Γ A B}
     Γ  A
     Γ  B
      -----------
     Γ  A  B

  `proj₁ :  {Γ A B}
     Γ  A  B
      -----------
     Γ  A

  `proj₂ :  {Γ A B}
     Γ  A  B
      -----------
     Γ  B

  -- 积的替代表示方法

  case× :  {Γ A B C}
     Γ  A  B
     Γ , A , B  C
      --------------
     Γ  C

缩减 de Bruijn 因子

length : Context  
length         =  zero
length (Γ , _)  =  suc (length Γ)

lookup : {Γ : Context}  {n : }  (p : n < length Γ)  Type
lookup {(_ , A)} {zero}    (s≤s z≤n)  =  A
lookup {(Γ , _)} {(suc n)} (s≤s p)    =  lookup p

count :  {Γ}  {n : }  (p : n < length Γ)  Γ  lookup p
count {_ , _} {zero}    (s≤s z≤n)  =  Z
count {Γ , _} {(suc n)} (s≤s p)    =  S (count p)

#_ :  {Γ}
   (n : )
   {n∈Γ : True (suc n ≤? length Γ)}
    --------------------------------
   Γ  lookup (toWitness n∈Γ)
#_ n {n∈Γ}  =  ` count (toWitness n∈Γ)

重命名

ext :  {Γ Δ}
   (∀ {A}        Γ  A      Δ  A)
    ---------------------------------
   (∀ {A B}  Γ , A  B  Δ , A  B)
ext ρ Z      =  Z
ext ρ (S x)  =  S (ρ x)

rename :  {Γ Δ}
   (∀ {A}  Γ  A  Δ  A)
    -----------------------
   (∀ {A}  Γ  A  Δ  A)
rename ρ (` x)          =  ` (ρ x)
rename ρ (ƛ N)          =  ƛ (rename (ext ρ) N)
rename ρ (L · M)        =  (rename ρ L) · (rename ρ M)
rename ρ (`zero)        =  `zero
rename ρ (`suc M)       =  `suc (rename ρ M)
rename ρ (case L M N)   =  case (rename ρ L) (rename ρ M) (rename (ext ρ) N)
rename ρ (μ N)          =  μ (rename (ext ρ) N)
rename ρ (con n)        =  con n
rename ρ (M `* N)       =  rename ρ M `* rename ρ N
rename ρ (`let M N)     =  `let (rename ρ M) (rename (ext ρ) N)
rename ρ `⟨ M , N      =  `⟨ rename ρ M , rename ρ N 
rename ρ (`proj₁ L)     =  `proj₁ (rename ρ L)
rename ρ (`proj₂ L)     =  `proj₂ (rename ρ L)
rename ρ (case× L M)    =  case× (rename ρ L) (rename (ext (ext ρ)) M)

同时代换

exts :  {Γ Δ}  (∀ {A}  Γ  A  Δ  A)  (∀ {A B}  Γ , A  B  Δ , A  B)
exts σ Z      =  ` Z
exts σ (S x)  =  rename S_ (σ x)

subst :  {Γ Δ}  (∀ {C}  Γ  C  Δ  C)  (∀ {C}  Γ  C  Δ  C)
subst σ (` k)          =  σ k
subst σ (ƛ N)          =  ƛ (subst (exts σ) N)
subst σ (L · M)        =  (subst σ L) · (subst σ M)
subst σ (`zero)        =  `zero
subst σ (`suc M)       =  `suc (subst σ M)
subst σ (case L M N)   =  case (subst σ L) (subst σ M) (subst (exts σ) N)
subst σ (μ N)          =  μ (subst (exts σ) N)
subst σ (con n)        =  con n
subst σ (M `* N)       =  subst σ M `* subst σ N
subst σ (`let M N)     =  `let (subst σ M) (subst (exts σ) N)
subst σ `⟨ M , N      =  `⟨ subst σ M , subst σ N 
subst σ (`proj₁ L)     =  `proj₁ (subst σ L)
subst σ (`proj₂ L)     =  `proj₂ (subst σ L)
subst σ (case× L M)    =  case× (subst σ L) (subst (exts (exts σ)) M)

单个和双重代换

_[_] :  {Γ A B}
   Γ , B  A
   Γ  B
    ---------
   Γ  A
_[_] {Γ} {A} {B} N M =  subst {Γ , B} {Γ} σ {A} N
  where
  σ :  {A}  Γ , B  A  Γ  A
  σ Z      =  M
  σ (S x)  =  ` x

_[_][_] :  {Γ A B C}
   Γ , A , B  C
   Γ  A
   Γ  B
    -------------
   Γ  C
_[_][_] {Γ} {A} {B} N V W =  subst {Γ , A , B} {Γ} σ N
  where
  σ :  {C}  Γ , A , B  C  Γ  C
  σ Z          =  W
  σ (S Z)      =  V
  σ (S (S x))  =  ` x

data Value :  {Γ A}  Γ  A  Set where

  -- 函数

  V-ƛ :  {Γ A B} {N : Γ , A  B}
      ---------------------------
     Value (ƛ N)

  -- 自然数

  V-zero :  {Γ}
      -----------------
     Value (`zero {Γ})

  V-suc_ :  {Γ} {V : Γ  `ℕ}
     Value V
      --------------
     Value (`suc V)

  -- 原语数字

  V-con :  {Γ n}
      -----------------
     Value (con {Γ} n)

  -- 积

  V-⟨_,_⟩ :  {Γ A B} {V : Γ  A} {W : Γ  B}
     Value V
     Value W
      ----------------
     Value `⟨ V , W 

在给出的参数无法确定隐式参数时,我们需要给出隐式参数。

归约

infix 2 _—→_

data _—→_ :  {Γ A}  (Γ  A)  (Γ  A)  Set where

  -- 函数

  ξ-·₁ :  {Γ A B} {L L′ : Γ  A  B} {M : Γ  A}
     L —→ L′
      ---------------
     L · M —→ L′ · M

  ξ-·₂ :  {Γ A B} {V : Γ  A  B} {M M′ : Γ  A}
     Value V
     M —→ M′
      ---------------
     V · M —→ V · M′

  β-ƛ :  {Γ A B} {N : Γ , A  B} {V : Γ  A}
     Value V
      --------------------
     (ƛ N) · V —→ N [ V ]

  -- 自然数

  ξ-suc :  {Γ} {M M′ : Γ  `ℕ}
     M —→ M′
      -----------------
     `suc M —→ `suc M′

  ξ-case :  {Γ A} {L L′ : Γ  `ℕ} {M : Γ  A} {N : Γ , `ℕ  A}
     L —→ L′
      -------------------------
     case L M N —→ case L′ M N

  β-zero :   {Γ A} {M : Γ  A} {N : Γ , `ℕ  A}
      -------------------
     case `zero M N —→ M

  β-suc :  {Γ A} {V : Γ  `ℕ} {M : Γ  A} {N : Γ , `ℕ  A}
     Value V
      ----------------------------
     case (`suc V) M N —→ N [ V ]

  -- 不动点

  β-μ :  {Γ A} {N : Γ , A  A}
      ----------------
     μ N —→ N [ μ N ]

  -- 原语数字

  ξ-*₁ :  {Γ} {L L′ M : Γ  Nat}
     L —→ L′
      -----------------
     L `* M —→ L′ `* M

  ξ-*₂ :  {Γ} {V M M′ : Γ  Nat}
     Value V
     M —→ M′
      -----------------
     V `* M —→ V `* M′

  δ-* :  {Γ c d}
      ---------------------------------
     con {Γ} c `* con d —→ con (c * d)

  -- let

  ξ-let :  {Γ A B} {M M′ : Γ  A} {N : Γ , A  B}
     M —→ M′
      ---------------------
     `let M N —→ `let M′ N

  β-let :  {Γ A B} {V : Γ  A} {N : Γ , A  B}
     Value V
      -------------------
     `let V N —→ N [ V ]

  -- 积

  ξ-⟨,⟩₁ :  {Γ A B} {M M′ : Γ  A} {N : Γ  B}
     M —→ M′
      -------------------------
     `⟨ M , N  —→ `⟨ M′ , N 

  ξ-⟨,⟩₂ :  {Γ A B} {V : Γ  A} {N N′ : Γ  B}
     Value V
     N —→ N′
      -------------------------
     `⟨ V , N  —→ `⟨ V , N′ 

  ξ-proj₁ :  {Γ A B} {L L′ : Γ  A  B}
     L —→ L′
      ---------------------
     `proj₁ L —→ `proj₁ L′

  ξ-proj₂ :  {Γ A B} {L L′ : Γ  A  B}
     L —→ L′
      ---------------------
     `proj₂ L —→ `proj₂ L′

  β-proj₁ :  {Γ A B} {V : Γ  A} {W : Γ  B}
     Value V
     Value W
      ----------------------
     `proj₁ `⟨ V , W  —→ V

  β-proj₂ :  {Γ A B} {V : Γ  A} {W : Γ  B}
     Value V
     Value W
      ----------------------
     `proj₂ `⟨ V , W  —→ W

  -- 积的替代表示方式

  ξ-case× :  {Γ A B C} {L L′ : Γ  A  B} {M : Γ , A , B  C}
     L —→ L′
      -----------------------
     case× L M —→ case× L′ M

  β-case× :  {Γ A B C} {V : Γ  A} {W : Γ  B} {M : Γ , A , B  C}
     Value V
     Value W
      ----------------------------------
     case× `⟨ V , W  M —→ M [ V ][ W ]

自反传递闭包

infix  2 _—↠_
infix  1 begin_
infixr 2 _—→⟨_⟩_
infix  3 _∎

data _—↠_ {Γ A} : (Γ  A)  (Γ  A)  Set where

  _∎ : (M : Γ  A)
      ------
     M —↠ M

  step—→ : (L : Γ  A) {M N : Γ  A}
     M —↠ N
     L —→ M
      ------
     L —↠ N

pattern _—→⟨_⟩_ L L—→M M—↠N = step—→ L M—↠N L—→M

begin_ :  {Γ A} {M N : Γ  A}
   M —↠ N
    ------
   M —↠ N
begin M—↠N = M—↠N

值不再归约

V¬—→ :  {Γ A} {M N : Γ  A}
   Value M
    ----------
   ¬ (M —→ N)
V¬—→ V-ƛ          ()
V¬—→ V-zero       ()
V¬—→ (V-suc VM)   (ξ-suc M—→M′)     =  V¬—→ VM M—→M′
V¬—→ V-con        ()
V¬—→ V-⟨ VM , _  (ξ-⟨,⟩₁ M—→M′)    =  V¬—→ VM M—→M′
V¬—→ V-⟨ _ , VN  (ξ-⟨,⟩₂ _ N—→N′)  =  V¬—→ VN N—→N′

可进性

data Progress {A} (M :   A) : Set where

  step :  {N :   A}
     M —→ N
      ----------
     Progress M

  done :
      Value M
      ----------
     Progress M

progress :  {A}
   (M :   A)
    -----------
   Progress M
progress (` ())
progress (ƛ N)                              =  done V-ƛ
progress (L · M) with progress L
...    | step L—→L′                         =  step (ξ-·₁ L—→L′)
...    | done V-ƛ with progress M
...        | step M—→M′                     =  step (ξ-·₂ V-ƛ M—→M′)
...        | done VM                        =  step (β-ƛ VM)
progress (`zero)                            =  done V-zero
progress (`suc M) with progress M
...    | step M—→M′                         =  step (ξ-suc M—→M′)
...    | done VM                            =  done (V-suc VM)
progress (case L M N) with progress L
...    | step L—→L′                         =  step (ξ-case L—→L′)
...    | done V-zero                        =  step β-zero
...    | done (V-suc VL)                    =  step (β-suc VL)
progress (μ N)                              =  step β-μ
progress (con n)                            =  done V-con
progress (L `* M) with progress L
...    | step L—→L′                         =  step (ξ-*₁ L—→L′)
...    | done V-con with progress M
...        | step M—→M′                     =  step (ξ-*₂ V-con M—→M′)
...        | done V-con                     =  step δ-*
progress (`let M N) with progress M
...    | step M—→M′                         =  step (ξ-let M—→M′)
...    | done VM                            =  step (β-let VM)
progress `⟨ M , N  with progress M
...    | step M—→M′                         =  step (ξ-⟨,⟩₁ M—→M′)
...    | done VM with progress N
...        | step N—→N′                     =  step (ξ-⟨,⟩₂ VM N—→N′)
...        | done VN                        =  done (V-⟨ VM , VN )
progress (`proj₁ L) with progress L
...    | step L—→L′                         =  step (ξ-proj₁ L—→L′)
...    | done (V-⟨ VM , VN )               =  step (β-proj₁ VM VN)
progress (`proj₂ L) with progress L
...    | step L—→L′                         =  step (ξ-proj₂ L—→L′)
...    | done (V-⟨ VM , VN )               =  step (β-proj₂ VM VN)
progress (case× L M) with progress L
...    | step L—→L′                         =  step (ξ-case× L—→L′)
...    | done (V-⟨ VM , VN )               =  step (β-case× VM VN)

求值

record Gas : Set where
  constructor gas
  field
    amount : 

data Finished {Γ A} (N : Γ  A) : Set where

   done :
       Value N
       ----------
      Finished N

   out-of-gas :
       ----------
       Finished N

data Steps {A} :   A  Set where

  steps : {L N :   A}
     L —↠ N
     Finished N
      ----------
     Steps L

eval :  {A}
   Gas
   (L :   A)
    -----------
   Steps L
eval (gas zero)    L                     =  steps (L ) out-of-gas
eval (gas (suc m)) L with progress L
... | done VL                            =  steps (L ) (done VL)
... | step {M} L—→M with eval (gas m) M
...    | steps M—↠N fin                  =  steps (L —→⟨ L—→M  M—↠N) fin

例子

cube :   Nat  Nat
cube = ƛ (# 0 `* # 0 `* # 0)

_ : cube · con 2 —↠ con 8
_ =
  begin
    cube · con 2
  —→⟨ β-ƛ V-con 
    con 2 `* con 2 `* con 2
  —→⟨ ξ-*₁ δ-* 
    con 4 `* con 2
  —→⟨ δ-* 
    con 8
  

exp10 :   Nat  Nat
exp10 = ƛ (`let (# 0 `* # 0)
            (`let (# 0 `* # 0)
              (`let (# 0 `* # 2)
                (# 0 `* # 0))))

_ : exp10 · con 2 —↠ con 1024
_ =
  begin
    exp10 · con 2
  —→⟨ β-ƛ V-con 
    `let (con 2 `* con 2) (`let (# 0 `* # 0) (`let (# 0 `* con 2) (# 0 `* # 0)))
  —→⟨ ξ-let δ-* 
    `let (con 4) (`let (# 0 `* # 0) (`let (# 0 `* con 2) (# 0 `* # 0)))
  —→⟨ β-let V-con 
    `let (con 4 `* con 4) (`let (# 0 `* con 2) (# 0 `* # 0))
  —→⟨ ξ-let δ-* 
    `let (con 16) (`let (# 0 `* con 2) (# 0 `* # 0))
  —→⟨ β-let V-con 
    `let (con 16 `* con 2) (# 0 `* # 0)
  —→⟨ ξ-let δ-* 
    `let (con 32) (# 0 `* # 0)
  —→⟨ β-let V-con 
    con 32 `* con 32
  —→⟨ δ-* 
    con 1024
  

swap× :  {A B}    A  B  B  A
swap× = ƛ `⟨ `proj₂ (# 0) , `proj₁ (# 0) 

_ : swap× · `⟨ con 42 , `zero  —↠ `⟨ `zero , con 42 
_ =
  begin
    swap× · `⟨ con 42 , `zero 
  —→⟨ β-ƛ V-⟨ V-con , V-zero  
    `⟨ `proj₂ `⟨ con 42 , `zero  , `proj₁ `⟨ con 42 , `zero  
  —→⟨ ξ-⟨,⟩₁ (β-proj₂ V-con V-zero) 
    `⟨ `zero , `proj₁ `⟨ con 42 , `zero  
  —→⟨ ξ-⟨,⟩₂ V-zero (β-proj₁ V-con V-zero) 
    `⟨ `zero , con 42 
  

swap×-case :  {A B}    A  B  B  A
swap×-case = ƛ case× (# 0) `⟨ # 0 , # 1 

_ : swap×-case · `⟨ con 42 , `zero  —↠ `⟨ `zero , con 42 
_ =
  begin
     swap×-case · `⟨ con 42 , `zero 
   —→⟨ β-ƛ V-⟨ V-con , V-zero  
     case× `⟨ con 42 , `zero  `⟨ # 0 , # 1 
   —→⟨ β-case× V-con V-zero 
     `⟨ `zero , con 42 
   

练习 More (推荐和实践)

形式化本章中定义的剩余构造。 修改本文件来完成你的改动。 求值每一个例子,如果需要时将其应用于数据,来确认它返回期待的答案:

  • 和(推荐)
  • 单元类型(实践)
  • 单元类型的替代表示方法(实践)
  • 空类型(推荐)
  • 列表(实践)

用下面的分隔符来标出你添加的代码:

-- begin
-- end

练习 double-subst(延伸)

证明双重代换等同于两个单独代换。

postulate
  double-subst :
     {Γ A B C} {V : Γ  A} {W : Γ  B} {N : Γ , A , B  C} 
      N [ V ][ W ]  (N [ rename S_ W ]) [ V ]

注意到我们需要交换参数,而且 W 的语境需要用重命名来调整,使得右手边的项保持良类型。

测试例子

我们重复 DeBruijn 章节中的测试例子, 来保证我们在扩展基本演算时没有破坏原演算的任何性质。

two :  {Γ}  Γ  `ℕ
two = `suc `suc `zero

plus :  {Γ}  Γ  `ℕ  `ℕ  `ℕ
plus = μ ƛ ƛ (case (# 1) (# 0) (`suc (# 3 · # 0 · # 1)))

2+2 :  {Γ}  Γ  `ℕ
2+2 = plus · two · two

Ch : Type  Type
Ch A  =  (A  A)  A  A

twoᶜ :  {Γ A}  Γ  Ch A
twoᶜ = ƛ ƛ (# 1 · (# 1 · # 0))

plusᶜ :  {Γ A}  Γ  Ch A  Ch A  Ch A
plusᶜ = ƛ ƛ ƛ ƛ (# 3 · # 1 · (# 2 · # 1 · # 0))

sucᶜ :  {Γ}  Γ  `ℕ  `ℕ
sucᶜ = ƛ `suc (# 0)

2+2ᶜ :  {Γ}  Γ  `ℕ
2+2ᶜ = plusᶜ · twoᶜ · twoᶜ · sucᶜ · `zero

Unicode

本章中使用了以下 Unicode:

σ  U+03C3  GREEK SMALL LETTER SIGMA (\Gs or \sigma)
†  U+2020  DAGGER (\dag)
‡  U+2021  DOUBLE DAGGER (\ddag)