revised notation for Lambda, PandP
This commit is contained in:
parent
62b25bad76
commit
ba4dd3e84b
2 changed files with 408 additions and 405 deletions
|
@ -11,7 +11,7 @@ module plta.Lambda where
|
|||
[This chapter was originally based on Chapter _Stlc_
|
||||
of _Software Foundations_ (_Programming Language Foundations_).
|
||||
It has now been updated, but if you spot any plagiarism
|
||||
please let me know. -- P]
|
||||
please let me know. – P]
|
||||
|
||||
The _lambda-calculus_, first published by the logician Alonzo Church in
|
||||
1932, is a core calculus with only three syntactic constructs:
|
||||
|
@ -67,7 +67,7 @@ open import Relation.Nullary.Negation using (¬?)
|
|||
|
||||
Terms have seven constructs. Three are for the core lambda calculus:
|
||||
|
||||
* Variables `⌊ x ⌋`
|
||||
* Variables `` x`
|
||||
* Abstractions `ƛ x ⇒ N`
|
||||
* Applications `L · M`
|
||||
|
||||
|
@ -94,7 +94,7 @@ correspond to introduction rules and deconstructors to eliminators.
|
|||
Here is the syntax of terms in BNF.
|
||||
|
||||
L, M, N ::=
|
||||
⌊ x ⌋ | ƛ x ⇒ N | L · M |
|
||||
` x | ƛ x ⇒ N | L · M |
|
||||
`zero | `suc M | `case L [zero⇒ M |suc x ⇒ N] |
|
||||
μ x ⇒ M
|
||||
|
||||
|
@ -107,9 +107,10 @@ infix 6 ƛ_⇒_
|
|||
infix 6 μ_⇒_
|
||||
infixl 7 _·_
|
||||
infix 8 `suc_
|
||||
infix 9 `_
|
||||
|
||||
data Term : Set where
|
||||
⌊_⌋ : Id → Term
|
||||
`_ : Id → Term
|
||||
ƛ_⇒_ : Id → Term → Term
|
||||
_·_ : Term → Term → Term
|
||||
`zero : Term
|
||||
|
@ -134,9 +135,9 @@ two = `suc `suc `zero
|
|||
|
||||
plus : Term
|
||||
plus = μ "+" ⇒ ƛ "m" ⇒ ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋
|
||||
[zero⇒ ⌊ "n" ⌋
|
||||
|suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋) ]
|
||||
`case ` "m"
|
||||
[zero⇒ ` "n"
|
||||
|suc "m" ⇒ `suc (` "+" · ` "m" · ` "n") ]
|
||||
|
||||
four : Term
|
||||
four = plus · two · two
|
||||
|
@ -160,14 +161,14 @@ function that adds Church numerals, a function to compute successor,
|
|||
and a term that computes two plus two.
|
||||
\begin{code}
|
||||
twoᶜ : Term
|
||||
twoᶜ = ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)
|
||||
twoᶜ = ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · ` "z")
|
||||
|
||||
plusᶜ : Term
|
||||
plusᶜ = ƛ "m" ⇒ ƛ "n" ⇒ ƛ "s" ⇒ ƛ "z" ⇒
|
||||
⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)
|
||||
` "m" · ` "s" · (` "n" · ` "s" · ` "z")
|
||||
|
||||
sucᶜ : Term
|
||||
sucᶜ = ƛ "n" ⇒ `suc (⌊ "n" ⌋)
|
||||
sucᶜ = ƛ "n" ⇒ `suc (` "n")
|
||||
|
||||
fourᶜ : Term
|
||||
fourᶜ = plusᶜ · twoᶜ · twoᶜ · sucᶜ · `zero
|
||||
|
@ -198,7 +199,7 @@ two natural numbers.
|
|||
### Formal vs informal
|
||||
|
||||
In informal presentation of formal semantics, one uses choice of
|
||||
variable name to disambiguate and writes `x` rather than `⌊ x ⌋`
|
||||
variable name to disambiguate and writes `x` rather than `` x`
|
||||
for a term that is a variable. Agda requires we distinguish.
|
||||
|
||||
Similarly, informal presentation often use the same notation for
|
||||
|
@ -218,10 +219,10 @@ and `N` the _body_ of the abstraction. A central feature
|
|||
of lambda calculus is that consistent renaming of bound variables
|
||||
leaves the meaning of a term unchanged. Thus the five terms
|
||||
|
||||
* `` ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ``
|
||||
* `` ƛ "f" ⇒ ƛ "x" ⇒ ⌊ "f" ⌋ · (⌊ "f" ⌋ · ⌊ "x" ⌋) ``
|
||||
* `` ƛ "sam" ⇒ ƛ "zelda" ⇒ ⌊ "sam" ⌋ · (⌊ "sam" ⌋ · ⌊ "zelda" ⌋) ``
|
||||
* `` ƛ "z" ⇒ ƛ "s" ⇒ ⌊ "z" ⌋ · (⌊ "z" ⌋ · ⌊ "s" ⌋) ``
|
||||
* `` ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · ` "z") ``
|
||||
* `` ƛ "f" ⇒ ƛ "x" ⇒ ` "f" · (` "f" · ` "x") ``
|
||||
* `` ƛ "sam" ⇒ ƛ "zelda" ⇒ ` "sam" · (` "sam" · ` "zelda") ``
|
||||
* `` ƛ "z" ⇒ ƛ "s" ⇒ ` "z" · (` "z" · ` "s") ``
|
||||
* `` ƛ "😇" ⇒ ƛ "😈" ⇒ # "😇" · (# "😇" · # "😈" ) ``
|
||||
|
||||
are all considered equivalent. Following the convention introduced
|
||||
|
@ -231,13 +232,13 @@ this equivalence relation is called _alpha renaming_.
|
|||
As we descend from a term into its subterms, variables
|
||||
that are bound may become free. Consider the following terms.
|
||||
|
||||
* `` ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ``
|
||||
* `` ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · ` "z") ``
|
||||
has both `s` and `z` as bound variables.
|
||||
|
||||
* `` ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ``
|
||||
* `` ƛ "z" ⇒ ` "s" · (` "s" · ` "z") ``
|
||||
has `s` bound and `z` free.
|
||||
|
||||
* `` ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ``
|
||||
* `` ` "s" · (` "s" · ` "z") ``
|
||||
has both `s` and `z` as free variables.
|
||||
|
||||
We say that a term with no free variables is _closed_; otherwise it is
|
||||
|
@ -247,12 +248,12 @@ two are open.
|
|||
Different occurrences of a variable may be bound and free.
|
||||
In the term
|
||||
|
||||
(ƛ "x" ⇒ ⌊ "x" ⌋) · ⌊ "x" ⌋
|
||||
(ƛ "x" ⇒ ` "x") · ` "x"
|
||||
|
||||
the inner occurrence of `x` is bound while the outer occurrence is free.
|
||||
By alpha renaming, the term above is equivalent to
|
||||
|
||||
(ƛ "y" ⇒ ⌊ "y" ⌋) · ⌊ "x" ⌋
|
||||
(ƛ "y" ⇒ ` "y") · ` "x"
|
||||
|
||||
in which `y` is bound and `x` is free. A common convention, called the
|
||||
_Barendregt convention_, is to use alpha renaming to ensure that the bound
|
||||
|
@ -264,17 +265,17 @@ Case and recursion also introduce bound variables, which are also subject
|
|||
to alpha renaming. In the term
|
||||
|
||||
μ "+" ⇒ ƛ "m" ⇒ ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋
|
||||
[zero⇒ ⌊ "n" ⌋
|
||||
|suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋) ]
|
||||
`case ` "m"
|
||||
[zero⇒ ` "n"
|
||||
|suc "m" ⇒ `suc (` "+" · ` "m" · ` "n") ]
|
||||
|
||||
notice that there are two binding occurrences of `m`, one in the first
|
||||
line and one in the last line. It is equivalent to the following term,
|
||||
|
||||
μ "plus" ⇒ ƛ "x" ⇒ ƛ "y" ⇒
|
||||
`case ⌊ "x" ⌋
|
||||
[zero⇒ ⌊ "y" ⌋
|
||||
|suc "x′" ⇒ `suc (⌊ "plus" ⌋ · ⌊ "x′" ⌋ · ⌊ "y" ⌋) ]
|
||||
`case ` "x"
|
||||
[zero⇒ ` "y"
|
||||
|suc "x′" ⇒ `suc (` "plus" · ` "x′" · ` "y") ]
|
||||
|
||||
where the two binding occurrences corresponding to `m` now have distinct
|
||||
names, `x` and `x′`.
|
||||
|
@ -342,13 +343,13 @@ Substitution plays a key role in defining the
|
|||
operational semantics of function application.
|
||||
For instance, we have
|
||||
|
||||
(ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)) · sucᶜ · `zero
|
||||
⟶
|
||||
(ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · ` "z")) · sucᶜ · `zero
|
||||
↦
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · "z")) · `zero
|
||||
⟶
|
||||
↦
|
||||
sucᶜ · (sucᶜ · `zero)
|
||||
|
||||
where we substitute `sucᶜ` for `` ⌊ "s" ⌋ `` and `` `zero `` for `` ⌊ "z" ⌋ ``
|
||||
where we substitute `sucᶜ` for `` ` "s" `` and `` `zero `` for `` ` "z" ``
|
||||
in the body of the function abstraction.
|
||||
|
||||
We write substitution as `N [ x := V ]`, meaning
|
||||
|
@ -360,19 +361,19 @@ usually substitute values.
|
|||
|
||||
Here are some examples:
|
||||
|
||||
* `` (sucᶜ · (sucᶜ · ⌊ "z" ⌋)) [ "z" := `zero ] `` yields
|
||||
* `` (sucᶜ · (sucᶜ · ` "z")) [ "z" := `zero ] `` yields
|
||||
`` sucᶜ · (sucᶜ · `zero) ``
|
||||
* `` (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)) [ "s" := sucᶜ ] `` yields
|
||||
ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋) ``
|
||||
* `` (ƛ "x" ⇒ ⌊ "y" ⌋) [ "y" := `zero ] `` yields `` ƛ "x" ⇒ `zero ``
|
||||
* `` (ƛ "x" ⇒ ⌊ "x" ⌋) [ "x" := `zero ] `` yields `` ƛ "x" ⇒ ⌊ "x" ⌋ ``
|
||||
* `` (ƛ "y" ⇒ ⌊ "y" ⌋) [ "x" := `zero ] `` yields `` ƛ "x" ⇒ ⌊ "x" ⌋ ``
|
||||
* `` (ƛ "z" ⇒ ` "s" · (` "s" · ` "z")) [ "s" := sucᶜ ] `` yields
|
||||
ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z") ``
|
||||
* `` (ƛ "x" ⇒ ` "y") [ "y" := `zero ] `` yields `` ƛ "x" ⇒ `zero ``
|
||||
* `` (ƛ "x" ⇒ ` "x") [ "x" := `zero ] `` yields `` ƛ "x" ⇒ ` "x" ``
|
||||
* `` (ƛ "y" ⇒ ` "y") [ "x" := `zero ] `` yields `` ƛ "x" ⇒ ` "x" ``
|
||||
|
||||
In the last but one example, substituting `` `zero `` for `x` in
|
||||
`` ƛ "x" ⇒ ⌊ "x" ⌋ `` does _not_ yield `` ƛ "x" ⇒ `zero ``,
|
||||
`` ƛ "x" ⇒ ` "x" `` does _not_ yield `` ƛ "x" ⇒ `zero ``,
|
||||
since `x` is bound in the lambda abstraction.
|
||||
The choice of bound names is irrelevant: both
|
||||
`` ƛ "x" ⇒ ⌊ "x" ⌋ `` and `` ƛ "y" ⇒ ⌊ "y" ⌋ `` stand for the
|
||||
`` ƛ "x" ⇒ ` "x" `` and `` ƛ "y" ⇒ ` "y" `` stand for the
|
||||
identity function. One way to think of this is that `x` within
|
||||
the body of the abstraction stands for a _different_ variable than
|
||||
`x` outside the abstraction, they just happen to have the same name.
|
||||
|
@ -382,13 +383,13 @@ when term substituted for the variable is closed. This is because
|
|||
substitution by terms that are _not_ closed may require renaming
|
||||
of bound variables. For example:
|
||||
|
||||
* `` (ƛ "x" ⇒ ⌊ "x" ⌋ · ⌊ "y" ⌋) [ "y" := ⌊ "x" ⌋ · ⌊ "y" ⌋ ] `` should not yield
|
||||
`` ƛ "x" ⇒ ⌊ "x" ⌋ · (⌊ "x" ⌋ · ⌊ "y" ⌋) ``
|
||||
* `` (ƛ "x" ⇒ ` "x" · ` "y") [ "y" := ` "x" · ` "y" ] `` should not yield
|
||||
`` ƛ "x" ⇒ ` "x" · (` "x" · ` "y") ``
|
||||
|
||||
Instead, we should rename the variables to avoid capture.
|
||||
|
||||
* `` (ƛ "x" ⇒ ⌊ "x" ⌋ · ⌊ "y" ⌋) [ "y" := ⌊ "x" ⌋ · ⌊ "y" ⌋ ] `` should yield
|
||||
`` ƛ "z" ⇒ ⌊ "z" ⌋ · (⌊ "x" ⌋ · ⌊ "y" ⌋) ``
|
||||
* `` (ƛ "x" ⇒ ` "x" · ` "y") [ "y" := ` "x" · ` "y" ] `` should yield
|
||||
`` ƛ "z" ⇒ ` "z" · (` "x" · ` "y") ``
|
||||
|
||||
Formal definition of substitution with suitable renaming is considerably
|
||||
more complex, so we avoid it by restricting to substitution by closed terms,
|
||||
|
@ -400,9 +401,9 @@ Here is the formal definition of substitution by closed terms in Agda.
|
|||
infix 9 _[_:=_]
|
||||
|
||||
_[_:=_] : Term → Id → Term → Term
|
||||
⌊ x ⌋ [ y := V ] with x ≟ y
|
||||
(` x) [ y := V ] with x ≟ y
|
||||
... | yes _ = V
|
||||
... | no _ = ⌊ x ⌋
|
||||
... | no _ = ` x
|
||||
(ƛ x ⇒ N) [ y := V ] with x ≟ y
|
||||
... | yes _ = ƛ x ⇒ N
|
||||
... | no _ = ƛ x ⇒ (N [ y := V ])
|
||||
|
@ -440,19 +441,19 @@ simply push substitution recursively into the subterms.
|
|||
Here is confirmation that the examples above are correct.
|
||||
|
||||
\begin{code}
|
||||
_ : (sucᶜ · sucᶜ · ⌊ "z" ⌋) [ "z" := `zero ] ≡ sucᶜ · sucᶜ · `zero
|
||||
_ : (sucᶜ · sucᶜ · ` "z") [ "z" := `zero ] ≡ sucᶜ · sucᶜ · `zero
|
||||
_ = refl
|
||||
|
||||
_ : (ƛ "z" ⇒ ⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "s" := sucᶜ ] ≡ ƛ "z" ⇒ sucᶜ · sucᶜ · ⌊ "z" ⌋
|
||||
_ : (ƛ "z" ⇒ ` "s" · ` "s" · ` "z") [ "s" := sucᶜ ] ≡ ƛ "z" ⇒ sucᶜ · sucᶜ · ` "z"
|
||||
_ = refl
|
||||
|
||||
_ : (ƛ "x" ⇒ ⌊ "y" ⌋) [ "y" := `zero ] ≡ ƛ "x" ⇒ `zero
|
||||
_ : (ƛ "x" ⇒ ` "y") [ "y" := `zero ] ≡ ƛ "x" ⇒ `zero
|
||||
_ = refl
|
||||
|
||||
_ : (ƛ "x" ⇒ ⌊ "x" ⌋) [ "x" := `zero ] ≡ ƛ "x" ⇒ ⌊ "x" ⌋
|
||||
_ : (ƛ "x" ⇒ ` "x") [ "x" := `zero ] ≡ ƛ "x" ⇒ ` "x"
|
||||
_ = refl
|
||||
|
||||
_ : (ƛ "y" ⇒ ⌊ "y" ⌋) [ "x" := `zero ] ≡ ƛ "y" ⇒ ⌊ "y" ⌋
|
||||
_ : (ƛ "y" ⇒ ` "y") [ "x" := `zero ] ≡ ƛ "y" ⇒ ` "y"
|
||||
_ = refl
|
||||
\end{code}
|
||||
|
||||
|
@ -460,11 +461,11 @@ _ = refl
|
|||
|
||||
What is the result of the following substitution?
|
||||
|
||||
(ƛ "y" ⇒ ⌊ "x" ⌋ · (ƛ "x" ⇒ ⌊ "x" ⌋)) [ "x" := `zero ]
|
||||
(ƛ "y" ⇒ ` "x" · (ƛ "x" ⇒ ` "x")) [ "x" := `zero ]
|
||||
|
||||
1. `` (ƛ "y" ⇒ ⌊ "x" ⌋ · (ƛ "x" ⇒ ⌊ "x" ⌋)) ``
|
||||
2. `` (ƛ "y" ⇒ ⌊ "x" ⌋ · (ƛ "x" ⇒ `zero)) ``
|
||||
3. `` (ƛ "y" ⇒ `zero · (ƛ "x" ⇒ ⌊ "x" ⌋)) ``
|
||||
1. `` (ƛ "y" ⇒ ` "x" · (ƛ "x" ⇒ ` "x")) ``
|
||||
2. `` (ƛ "y" ⇒ ` "x" · (ƛ "x" ⇒ `zero)) ``
|
||||
3. `` (ƛ "y" ⇒ `zero · (ƛ "x" ⇒ ` "x")) ``
|
||||
4. `` (ƛ "y" ⇒ `zero · (ƛ "x" ⇒ `zero)) ``
|
||||
|
||||
|
||||
|
@ -479,16 +480,16 @@ the argument for the variable in the abstraction.
|
|||
In an informal presentation of the operational semantics,
|
||||
the rules for reduction of applications are written as follows.
|
||||
|
||||
L ⟶ L′
|
||||
--------------- ξ·₁
|
||||
L · M ⟶ L′ · M
|
||||
L ↦ L′
|
||||
-------------- ξ-·₁
|
||||
L · M ↦ L′ · M
|
||||
|
||||
M ⟶ M′
|
||||
--------------- ξ·₂
|
||||
V · M ⟶ V · M′
|
||||
M ↦ M′
|
||||
-------------- ξ-·₂
|
||||
V · M ↦ V · M′
|
||||
|
||||
--------------------------------- βλ·
|
||||
(ƛ x ⇒ N) · V ⟶ N [ x := V ]
|
||||
---------------------------- β-ƛ
|
||||
(ƛ x ⇒ N) · V ↦ N [ x := V ]
|
||||
|
||||
The Agda version of the rules below will be similar, except that universal
|
||||
quantifications are made explicit, and so are the predicates that indicate
|
||||
|
@ -513,75 +514,84 @@ the bound variable by the entire fixpoint term.
|
|||
Here are the rules formalised in Agda.
|
||||
|
||||
\begin{code}
|
||||
infix 4 _⟶_
|
||||
infix 4 _↦_
|
||||
|
||||
data _⟶_ : Term → Term → Set where
|
||||
data _↦_ : Term → Term → Set where
|
||||
|
||||
ξ-·₁ : ∀ {L L′ M}
|
||||
→ L ⟶ L′
|
||||
→ L ↦ L′
|
||||
-----------------
|
||||
→ L · M ⟶ L′ · M
|
||||
→ L · M ↦ L′ · M
|
||||
|
||||
ξ-·₂ : ∀ {V M M′}
|
||||
→ Value V
|
||||
→ M ⟶ M′
|
||||
→ M ↦ M′
|
||||
-----------------
|
||||
→ V · M ⟶ V · M′
|
||||
→ V · M ↦ V · M′
|
||||
|
||||
β-ƛ· : ∀ {x N V}
|
||||
β-ƛ : ∀ {x N V}
|
||||
→ Value V
|
||||
------------------------------
|
||||
→ (ƛ x ⇒ N) · V ⟶ N [ x := V ]
|
||||
→ (ƛ x ⇒ N) · V ↦ N [ x := V ]
|
||||
|
||||
ξ-suc : ∀ {M M′}
|
||||
→ M ⟶ M′
|
||||
→ M ↦ M′
|
||||
------------------
|
||||
→ `suc M ⟶ `suc M′
|
||||
→ `suc M ↦ `suc M′
|
||||
|
||||
ξ-case : ∀ {x L L′ M N}
|
||||
→ L ⟶ L′
|
||||
→ L ↦ L′
|
||||
-----------------------------------------------------------------
|
||||
→ `case L [zero⇒ M |suc x ⇒ N ] ⟶ `case L′ [zero⇒ M |suc x ⇒ N ]
|
||||
→ `case L [zero⇒ M |suc x ⇒ N ] ↦ `case L′ [zero⇒ M |suc x ⇒ N ]
|
||||
|
||||
β-case-zero : ∀ {x M N}
|
||||
β-zero : ∀ {x M N}
|
||||
----------------------------------------
|
||||
→ `case `zero [zero⇒ M |suc x ⇒ N ] ⟶ M
|
||||
→ `case `zero [zero⇒ M |suc x ⇒ N ] ↦ M
|
||||
|
||||
β-case-suc : ∀ {x V M N}
|
||||
β-suc : ∀ {x V M N}
|
||||
→ Value V
|
||||
---------------------------------------------------
|
||||
→ `case `suc V [zero⇒ M |suc x ⇒ N ] ⟶ N [ x := V ]
|
||||
→ `case `suc V [zero⇒ M |suc x ⇒ N ] ↦ N [ x := V ]
|
||||
|
||||
β-μ : ∀ {x M}
|
||||
------------------------------
|
||||
→ μ x ⇒ M ⟶ M [ x := μ x ⇒ M ]
|
||||
→ μ x ⇒ M ↦ M [ x := μ x ⇒ M ]
|
||||
\end{code}
|
||||
|
||||
The reduction rules are carefully designed to ensure that subterms
|
||||
of a term are reduced to values before the whole term is reduced.
|
||||
This is referred to as _call by value_ reduction.
|
||||
|
||||
Further, we have arranged that subterms are reduced in a
|
||||
left-to-right order. This means that reduction is _deterministic_:
|
||||
for any term, there is at most one other term to which it reduces.
|
||||
Put another way, our reduction relation `↦` is in fact a function.
|
||||
|
||||
|
||||
#### Quiz
|
||||
|
||||
What does the following term step to?
|
||||
|
||||
(ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) ⟶ ???
|
||||
(ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") ↦ ???
|
||||
|
||||
1. `` (ƛ "x" ⇒ ⌊ "x" ⌋) ``
|
||||
2. `` (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) ``
|
||||
3. `` (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) ``
|
||||
1. `` (ƛ "x" ⇒ ` "x") ``
|
||||
2. `` (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") ``
|
||||
3. `` (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") ``
|
||||
|
||||
What does the following term step to?
|
||||
|
||||
(ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) ⟶ ???
|
||||
(ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") ↦ ???
|
||||
|
||||
1. `` (ƛ "x" ⇒ ⌊ "x" ⌋) ``
|
||||
2. `` (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) ``
|
||||
3. `` (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) · (ƛ "x" ⇒ ⌊ "x" ⌋) ``
|
||||
1. `` (ƛ "x" ⇒ ` "x") ``
|
||||
2. `` (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") ``
|
||||
3. `` (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") · (ƛ "x" ⇒ ` "x") ``
|
||||
|
||||
What does the following term step to? (Where `two` and `sucᶜ` are as defined above.)
|
||||
|
||||
two · sucᶜ · `zero ⟶ ???
|
||||
two · sucᶜ · `zero ↦ ???
|
||||
|
||||
1. `` sucᶜ · (sucᶜ · `zero) ``
|
||||
2. `` (ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · `zero ``
|
||||
2. `` (ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · `zero ``
|
||||
3. `` `zero ``
|
||||
|
||||
|
||||
|
@ -589,170 +599,155 @@ What does the following term step to? (Where `two` and `sucᶜ` are as defined
|
|||
|
||||
A single step is only part of the story. In general, we wish to repeatedly
|
||||
step a closed term until it reduces to a value. We do this by defining
|
||||
the reflexive and transitive closure `⟶*` of the step function `⟶`.
|
||||
the reflexive and transitive closure `↠` of the step relation `↦`.
|
||||
|
||||
The reflexive and transitive closure `⟶*` of an arbitrary relation `⟶`
|
||||
is the smallest relation that includes `⟶` and is also reflexive
|
||||
and transitive. We could define this directly, as follows.
|
||||
\begin{code}
|
||||
module Closure (A : Set) (_⟶_ : A → A → Set) where
|
||||
|
||||
data _⟶*_ : A → A → Set where
|
||||
|
||||
refl : ∀ {M}
|
||||
--------
|
||||
→ M ⟶* M
|
||||
|
||||
trans : ∀ {L M N}
|
||||
→ L ⟶* M
|
||||
→ M ⟶* N
|
||||
--------
|
||||
→ L ⟶* N
|
||||
|
||||
inc : ∀ {M N}
|
||||
→ M ⟶ N
|
||||
--------
|
||||
→ M ⟶* N
|
||||
\end{code}
|
||||
Here we use a module to define the reflexive and transitive
|
||||
closure of an arbitrary relation.
|
||||
The three clauses specify that `⟶*` is reflexive and transitive,
|
||||
and that `⟶` implies `⟶*`.
|
||||
|
||||
However, it will prove more convenient to define the transitive
|
||||
closure as a sequence of zero or more steps of the underlying
|
||||
relation, along lines similar to that for reasoning about
|
||||
chains of equalities
|
||||
We define reflexive and transitive closure as a sequence of zero or
|
||||
more steps of the underlying relation, along lines similar to that for
|
||||
reasoning about chains of equalities
|
||||
Chapter [Equality]({{ site.baseurl }}{% link out/plta/Equality.md %}).
|
||||
\begin{code}
|
||||
module Chain (A : Set) (_⟶_ : A → A → Set) where
|
||||
infix 2 _↠_
|
||||
infix 1 begin_
|
||||
infixr 2 _↦⟨_⟩_
|
||||
infix 3 _∎
|
||||
|
||||
infix 2 _⟶*_
|
||||
infix 1 begin_
|
||||
infixr 2 _⟶⟨_⟩_
|
||||
infix 3 _∎
|
||||
data _↠_ : Term → Term → Set where
|
||||
_∎ : ∀ M
|
||||
---------
|
||||
→ M ↠ M
|
||||
|
||||
data _⟶*_ : A → A → Set where
|
||||
_∎ : ∀ M
|
||||
---------
|
||||
→ M ⟶* M
|
||||
_↦⟨_⟩_ : ∀ L {M N}
|
||||
→ L ↦ M
|
||||
→ M ↠ N
|
||||
---------
|
||||
→ L ↠ N
|
||||
|
||||
_⟶⟨_⟩_ : ∀ L {M N}
|
||||
→ L ⟶ M
|
||||
→ M ⟶* N
|
||||
---------
|
||||
→ L ⟶* N
|
||||
|
||||
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
|
||||
begin M⟶*N = M⟶*N
|
||||
begin_ : ∀ {M N} → (M ↠ N) → (M ↠ N)
|
||||
begin M↠N = M↠N
|
||||
\end{code}
|
||||
We can read this as follows.
|
||||
|
||||
* From term `M`, we can take no steps,
|
||||
giving a step of type `M ⟶* M`.
|
||||
* From term `M`, we can take no steps, giving a step of type `M ↠ M`.
|
||||
It is written `M ∎`.
|
||||
|
||||
* From term `L` we can take a single of type `L ⟶ M`
|
||||
followed by zero or more steps of type `M ⟶* N`,
|
||||
giving a step of type `L ⟶* N`,
|
||||
It is written `L ⟨ L⟶M ⟩ M⟶*N`,
|
||||
where `L⟶M` and `M⟶*N` are steps of the appropriate type.
|
||||
* From term `L` we can take a single of type `L ↦ M` followed by zero
|
||||
or more steps of type `M ↠ N`, giving a step of type `L ↠ N`. It is
|
||||
written `L ↦⟨ L↦M ⟩ M↠N`, where `L↦M` and `M↠N` are steps of the
|
||||
appropriate type.
|
||||
|
||||
The notation is chosen to allow us to lay
|
||||
out example reductions in an appealing way,
|
||||
as we will see in the next section.
|
||||
The notation is chosen to allow us to lay out example reductions in an
|
||||
appealing way, as we will see in the next section.
|
||||
|
||||
We then instantiate the second module to our specific notion
|
||||
of reduction step.
|
||||
As alternative is to define reflexive and transitive closure directly,
|
||||
as the smallest relation that includes `↦` and is also reflexive
|
||||
and transitive. We could do so as follows.
|
||||
\begin{code}
|
||||
open Chain (Term) (_⟶_)
|
||||
data _↠′_ : Term → Term → Set where
|
||||
|
||||
step : ∀ {M N}
|
||||
→ M ↦ N
|
||||
------
|
||||
→ M ↠′ N
|
||||
|
||||
refl : ∀ {M}
|
||||
------
|
||||
→ M ↠′ M
|
||||
|
||||
trans : ∀ {L M N}
|
||||
→ L ↠′ M
|
||||
→ M ↠′ N
|
||||
------
|
||||
→ L ↠′ N
|
||||
\end{code}
|
||||
The three constructors specify, respectively, that `↠` includes `↦`
|
||||
and is reflexive and transitive.
|
||||
|
||||
It is a straightforward exercise to show the two are equivalent.
|
||||
|
||||
#### Exercise (`closure-equivalent`)
|
||||
#### Exercise (`↠≃↠′`)
|
||||
|
||||
Show that the two notions of reflexive and transitive closure
|
||||
above are equivalent.
|
||||
above are isomorphic.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Here is a sample reduction demonstrating that two plus two is four.
|
||||
\begin{code}
|
||||
_ : four ⟶* `suc `suc `suc `suc `zero
|
||||
_ : four ↠ `suc `suc `suc `suc `zero
|
||||
_ =
|
||||
begin
|
||||
plus · two · two
|
||||
⟶⟨ ξ-·₁ (ξ-·₁ β-μ) ⟩
|
||||
↦⟨ ξ-·₁ (ξ-·₁ β-μ) ⟩
|
||||
(ƛ "m" ⇒ ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · ⌊ "n" ⌋) ])
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (plus · ` "m" · ` "n") ])
|
||||
· two · two
|
||||
⟶⟨ ξ-·₁ (β-ƛ· (V-suc (V-suc V-zero))) ⟩
|
||||
↦⟨ ξ-·₁ (β-ƛ (V-suc (V-suc V-zero))) ⟩
|
||||
(ƛ "n" ⇒
|
||||
`case two [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · ⌊ "n" ⌋) ])
|
||||
`case two [zero⇒ ` "n" |suc "m" ⇒ `suc (plus · ` "m" · ` "n") ])
|
||||
· two
|
||||
⟶⟨ β-ƛ· (V-suc (V-suc V-zero)) ⟩
|
||||
`case two [zero⇒ two |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · two) ]
|
||||
⟶⟨ β-case-suc (V-suc V-zero) ⟩
|
||||
↦⟨ β-ƛ (V-suc (V-suc V-zero)) ⟩
|
||||
`case two [zero⇒ two |suc "m" ⇒ `suc (plus · ` "m" · two) ]
|
||||
↦⟨ β-suc (V-suc V-zero) ⟩
|
||||
`suc (plus · `suc `zero · two)
|
||||
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₁ β-μ)) ⟩
|
||||
↦⟨ ξ-suc (ξ-·₁ (ξ-·₁ β-μ)) ⟩
|
||||
`suc ((ƛ "m" ⇒ ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · ⌊ "n" ⌋) ])
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (plus · ` "m" · ` "n") ])
|
||||
· `suc `zero · two)
|
||||
⟶⟨ ξ-suc (ξ-·₁ (β-ƛ· (V-suc V-zero))) ⟩
|
||||
↦⟨ ξ-suc (ξ-·₁ (β-ƛ (V-suc V-zero))) ⟩
|
||||
`suc ((ƛ "n" ⇒
|
||||
`case `suc `zero [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · ⌊ "n" ⌋) ])
|
||||
`case `suc `zero [zero⇒ ` "n" |suc "m" ⇒ `suc (plus · ` "m" · ` "n") ])
|
||||
· two)
|
||||
⟶⟨ ξ-suc (β-ƛ· (V-suc (V-suc V-zero))) ⟩
|
||||
`suc (`case `suc `zero [zero⇒ two |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · two) ])
|
||||
⟶⟨ ξ-suc (β-case-suc V-zero) ⟩
|
||||
↦⟨ ξ-suc (β-ƛ (V-suc (V-suc V-zero))) ⟩
|
||||
`suc (`case `suc `zero [zero⇒ two |suc "m" ⇒ `suc (plus · ` "m" · two) ])
|
||||
↦⟨ ξ-suc (β-suc V-zero) ⟩
|
||||
`suc `suc (plus · `zero · two)
|
||||
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ β-μ))) ⟩
|
||||
↦⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ β-μ))) ⟩
|
||||
`suc `suc ((ƛ "m" ⇒ ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · ⌊ "n" ⌋) ])
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (plus · ` "m" · ` "n") ])
|
||||
· `zero · two)
|
||||
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (β-ƛ· V-zero))) ⟩
|
||||
↦⟨ ξ-suc (ξ-suc (ξ-·₁ (β-ƛ V-zero))) ⟩
|
||||
`suc `suc ((ƛ "n" ⇒
|
||||
`case `zero [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · ⌊ "n" ⌋) ])
|
||||
`case `zero [zero⇒ ` "n" |suc "m" ⇒ `suc (plus · ` "m" · ` "n") ])
|
||||
· two)
|
||||
⟶⟨ ξ-suc (ξ-suc (β-ƛ· (V-suc (V-suc V-zero)))) ⟩
|
||||
`suc `suc (`case `zero [zero⇒ two |suc "m" ⇒ `suc (plus · ⌊ "m" ⌋ · two) ])
|
||||
⟶⟨ ξ-suc (ξ-suc β-case-zero) ⟩
|
||||
↦⟨ ξ-suc (ξ-suc (β-ƛ (V-suc (V-suc V-zero)))) ⟩
|
||||
`suc `suc (`case `zero [zero⇒ two |suc "m" ⇒ `suc (plus · ` "m" · two) ])
|
||||
↦⟨ ξ-suc (ξ-suc β-zero) ⟩
|
||||
`suc (`suc (`suc (`suc `zero)))
|
||||
∎
|
||||
\end{code}
|
||||
|
||||
And here is a similar sample reduction for Church numerals.
|
||||
\begin{code}
|
||||
_ : fourᶜ ⟶* `suc `suc `suc `suc `zero
|
||||
_ : fourᶜ ↠ `suc `suc `suc `suc `zero
|
||||
_ =
|
||||
begin
|
||||
(ƛ "m" ⇒ ƛ "n" ⇒ ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋))
|
||||
(ƛ "m" ⇒ ƛ "n" ⇒ ƛ "s" ⇒ ƛ "z" ⇒ ` "m" · ` "s" · (` "n" · ` "s" · ` "z"))
|
||||
· twoᶜ · twoᶜ · sucᶜ · `zero
|
||||
⟶⟨ ξ-·₁ (ξ-·₁ (ξ-·₁ (β-ƛ· V-ƛ))) ⟩
|
||||
(ƛ "n" ⇒ ƛ "s" ⇒ ƛ "z" ⇒ twoᶜ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋))
|
||||
↦⟨ ξ-·₁ (ξ-·₁ (ξ-·₁ (β-ƛ V-ƛ))) ⟩
|
||||
(ƛ "n" ⇒ ƛ "s" ⇒ ƛ "z" ⇒ twoᶜ · ` "s" · (` "n" · ` "s" · ` "z"))
|
||||
· twoᶜ · sucᶜ · `zero
|
||||
⟶⟨ ξ-·₁ (ξ-·₁ (β-ƛ· V-ƛ)) ⟩
|
||||
(ƛ "s" ⇒ ƛ "z" ⇒ twoᶜ · ⌊ "s" ⌋ · (twoᶜ · ⌊ "s" ⌋ · ⌊ "z" ⌋)) · sucᶜ · `zero
|
||||
⟶⟨ ξ-·₁ (β-ƛ· V-ƛ) ⟩
|
||||
(ƛ "z" ⇒ twoᶜ · sucᶜ · (twoᶜ · sucᶜ · ⌊ "z" ⌋)) · `zero
|
||||
⟶⟨ β-ƛ· V-zero ⟩
|
||||
↦⟨ ξ-·₁ (ξ-·₁ (β-ƛ V-ƛ)) ⟩
|
||||
(ƛ "s" ⇒ ƛ "z" ⇒ twoᶜ · ` "s" · (twoᶜ · ` "s" · ` "z")) · sucᶜ · `zero
|
||||
↦⟨ ξ-·₁ (β-ƛ V-ƛ) ⟩
|
||||
(ƛ "z" ⇒ twoᶜ · sucᶜ · (twoᶜ · sucᶜ · ` "z")) · `zero
|
||||
↦⟨ β-ƛ V-zero ⟩
|
||||
twoᶜ · sucᶜ · (twoᶜ · sucᶜ · `zero)
|
||||
⟶⟨ ξ-·₁ (β-ƛ· V-ƛ) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · (twoᶜ · sucᶜ · `zero)
|
||||
⟶⟨ ξ-·₂ V-ƛ (ξ-·₁ (β-ƛ· V-ƛ)) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · ((ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · `zero)
|
||||
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· V-zero) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · (sucᶜ · (sucᶜ · `zero))
|
||||
⟶⟨ ξ-·₂ V-ƛ (ξ-·₂ V-ƛ (β-ƛ· V-zero)) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · (sucᶜ · (`suc `zero))
|
||||
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· (V-suc V-zero)) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ⌊ "z" ⌋)) · (`suc `suc `zero)
|
||||
⟶⟨ β-ƛ· (V-suc (V-suc V-zero)) ⟩
|
||||
↦⟨ ξ-·₁ (β-ƛ V-ƛ) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · (twoᶜ · sucᶜ · `zero)
|
||||
↦⟨ ξ-·₂ V-ƛ (ξ-·₁ (β-ƛ V-ƛ)) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · ((ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · `zero)
|
||||
↦⟨ ξ-·₂ V-ƛ (β-ƛ V-zero) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · (sucᶜ · (sucᶜ · `zero))
|
||||
↦⟨ ξ-·₂ V-ƛ (ξ-·₂ V-ƛ (β-ƛ V-zero)) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · (sucᶜ · (`suc `zero))
|
||||
↦⟨ ξ-·₂ V-ƛ (β-ƛ (V-suc V-zero)) ⟩
|
||||
(ƛ "z" ⇒ sucᶜ · (sucᶜ · ` "z")) · (`suc `suc `zero)
|
||||
↦⟨ β-ƛ (V-suc (V-suc V-zero)) ⟩
|
||||
sucᶜ · (sucᶜ · `suc `suc `zero)
|
||||
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· (V-suc (V-suc V-zero))) ⟩
|
||||
↦⟨ ξ-·₂ V-ƛ (β-ƛ (V-suc (V-suc V-zero))) ⟩
|
||||
sucᶜ · (`suc `suc `suc `zero)
|
||||
⟶⟨ β-ƛ· (V-suc (V-suc (V-suc V-zero))) ⟩
|
||||
↦⟨ β-ƛ (V-suc (V-suc (V-suc V-zero))) ⟩
|
||||
`suc (`suc (`suc (`suc `zero)))
|
||||
∎
|
||||
\end{code}
|
||||
|
@ -803,7 +798,7 @@ Thus,
|
|||
|
||||
* What is the type of the following term?
|
||||
|
||||
ƛ "s" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · `zero)
|
||||
ƛ "s" ⇒ ` "s" · (` "s" · `zero)
|
||||
|
||||
1. `` (`ℕ ⇒ `ℕ) ⇒ (`ℕ ⇒ `ℕ) ``
|
||||
2. `` (`ℕ ⇒ `ℕ) ⇒ `ℕ ``
|
||||
|
@ -816,7 +811,7 @@ Thus,
|
|||
|
||||
* What is the type of the following term?
|
||||
|
||||
(ƛ "s" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · `zero)) · sucᵐ
|
||||
(ƛ "s" ⇒ ` "s" · (` "s" · `zero)) · sucᵐ
|
||||
|
||||
1. `` (`ℕ ⇒ `ℕ) ⇒ (`ℕ ⇒ `ℕ) ``
|
||||
2. `` (`ℕ ⇒ `ℕ) ⇒ `ℕ ``
|
||||
|
@ -910,9 +905,9 @@ and indicates in context `Γ` that term `M` has type `A`.
|
|||
Context `Γ` provides types for all the free variables in `M`.
|
||||
For example
|
||||
|
||||
* `` ∅ , "s" ⦂ `ℕ ⇒ `ℕ , "z" ⦂ `ℕ ⊢ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ⦂ `ℕ ``
|
||||
* `` ∅ , "s" ⦂ `ℕ ⇒ `ℕ ⊢ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)) ⦂ `ℕ ⇒ `ℕ ``
|
||||
* `` ∅ ⊢ ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)) ⦂ (`ℕ ⇒ `ℕ) ⇒ `ℕ ⇒ `ℕ ``
|
||||
* `` ∅ , "s" ⦂ `ℕ ⇒ `ℕ , "z" ⦂ `ℕ ⊢ ` "s" · (` "s" · ` "z") ⦂ `ℕ ``
|
||||
* `` ∅ , "s" ⦂ `ℕ ⇒ `ℕ ⊢ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z")) ⦂ `ℕ ⇒ `ℕ ``
|
||||
* `` ∅ ⊢ ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · ` "z")) ⦂ (`ℕ ⇒ `ℕ) ⇒ `ℕ ⇒ `ℕ ``
|
||||
|
||||
Typing is formalised as follows.
|
||||
\begin{code}
|
||||
|
@ -923,7 +918,7 @@ data _⊢_⦂_ : Context → Term → Type → Set where
|
|||
Ax : ∀ {Γ x A}
|
||||
→ Γ ∋ x ⦂ A
|
||||
-------------
|
||||
→ Γ ⊢ ⌊ x ⌋ ⦂ A
|
||||
→ Γ ⊢ ` x ⦂ A
|
||||
|
||||
-- ⇒-I
|
||||
⊢ƛ : ∀ {Γ x N A B}
|
||||
|
@ -998,7 +993,7 @@ Here `_≟_` is the function that tests two identifiers for equality.
|
|||
We intend to apply the function only when the
|
||||
two arguments are indeed unequal, and indicate that the second
|
||||
case should never arise by postulating a term `impossible` of
|
||||
with the empty type `⊥`. If we use ^C ^N to normalise the term
|
||||
with the empty type `⊥`. If we use `C `N to normalise the term
|
||||
|
||||
"a" ≠ "a"
|
||||
|
||||
|
@ -1016,17 +1011,17 @@ evidence of _any_ proposition whatsoever, regardless of its truth.
|
|||
Type derivations correspond to trees. In informal notation, here
|
||||
is a type derivation for the Church numberal two:
|
||||
|
||||
∋s ∋s ∋z
|
||||
------------------- ⌊_⌋ ------------------- ⌊_⌋ --------------- ⌊_⌋
|
||||
Γ₂ ⊢ ⌊ "s" ⌋ ⦂ A ⇒ A Γ₂ ⊢ ⌊ "s" ⌋ ⦂ A ⇒ A Γ₂ ⊢ ⌊ "z" ⌋ ⦂ A
|
||||
------------------- ⌊_⌋ ------------------------------------------ _·_
|
||||
Γ₂ ⊢ ⌊ "s" ⌋ ⦂ A ⇒ A Γ₂ ⊢ ⌊ "s" ⌋ · ⌊ "z" ⌋ ⦂ A
|
||||
∋s ∋s ∋z
|
||||
------------------- `_ ------------------- `_ --------------- `_
|
||||
Γ₂ ⊢ ` "s" ⦂ A ⇒ A Γ₂ ⊢ ` "s" ⦂ A ⇒ A Γ₂ ⊢ ` "z" ⦂ A
|
||||
------------------- `_ ------------------------------------------ _·_
|
||||
Γ₂ ⊢ ` "s" ⦂ A ⇒ A Γ₂ ⊢ ` "s" · ` "z" ⦂ A
|
||||
-------------------------------------------------- _·_
|
||||
Γ₂ ⊢ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ⦂ A
|
||||
Γ₂ ⊢ ` "s" · (` "s" · ` "z") ⦂ A
|
||||
---------------------------------------------- ⊢ƛ
|
||||
Γ₁ ⊢ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ⦂ A ⇒ A
|
||||
Γ₁ ⊢ ƛ "z" ⇒ ` "s" · (` "s" · ` "z") ⦂ A ⇒ A
|
||||
---------------------------------------------------------- ⊢ƛ
|
||||
∅ ⊢ ƛ "s" ⇒ ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋) ⦂ A ⇒ A
|
||||
∅ ⊢ ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · ` "z") ⦂ A ⇒ A
|
||||
|
||||
where `∋s` and `∋z` abbreviate the two derivations:
|
||||
|
||||
|
@ -1113,12 +1108,12 @@ the outermost term in `sucᶜ` in `⊢ƛ`, which is typed using `ƛ`. The
|
|||
`ƛ` rule in turn takes one argument, which Agda leaves as a hole.
|
||||
|
||||
⊢sucᶜ = ⊢ƛ { }1
|
||||
?1 : ∅ , "n" ⦂ `ℕ ⊢ `suc ⌊ "n" ⌋ ⦂ `ℕ
|
||||
?1 : ∅ , "n" ⦂ `ℕ ⊢ `suc ` "n" ⦂ `ℕ
|
||||
|
||||
We can fill in the hole by type C-c C-r again.
|
||||
|
||||
⊢sucᶜ = ⊢ƛ (⊢suc { }2)
|
||||
?2 : ∅ , "n" ⦂ `ℕ ⊢ ⌊ "n" ⌋ ⦂ `ℕ
|
||||
?2 : ∅ , "n" ⦂ `ℕ ⊢ ` "n" ⦂ `ℕ
|
||||
|
||||
And again.
|
||||
|
||||
|
@ -1157,10 +1152,10 @@ the term `ƛ "x" ⇒ "x"` has type `A ⇒ A` for any type `A`.
|
|||
### Non-examples
|
||||
|
||||
We can also show that terms are _not_ typeable. For example, here is
|
||||
a formal proof that it is not possible to type the term `` `zero ·
|
||||
`suc `zero ``. In other words, no type `A` is the type of this term. It
|
||||
cannot be typed, because doing so requires that the first term in the
|
||||
application is both a natural and a function.
|
||||
a formal proof that it is not possible to type the term
|
||||
`` `zero · `suc `zero ``. It cannot be typed, because doing so
|
||||
requires that the first term in the application is both a natural and
|
||||
a function.
|
||||
|
||||
\begin{code}
|
||||
nope₁ : ∀ {A} → ¬ (∅ ⊢ `zero · `suc `zero ⦂ A)
|
||||
|
@ -1168,11 +1163,11 @@ nope₁ (() · _)
|
|||
\end{code}
|
||||
|
||||
As a second example, here is a formal proof that it is not possible to
|
||||
type `` ƛ "x" ⇒ ⌊ "x" ⌋ · ⌊ "x" ⌋ `` It cannot be typed, because
|
||||
type `` ƛ "x" ⇒ ` "x" · ` "x" `` It cannot be typed, because
|
||||
doing so requires types `A` and `B` such that `A ⇒ B ≡ A`.
|
||||
|
||||
\begin{code}
|
||||
nope₂ : ∀ {A} → ¬ (∅ ⊢ ƛ "x" ⇒ ⌊ "x" ⌋ · ⌊ "x" ⌋ ⦂ A)
|
||||
nope₂ : ∀ {A} → ¬ (∅ ⊢ ƛ "x" ⇒ ` "x" · ` "x" ⦂ A)
|
||||
nope₂ (⊢ƛ (Ax ∋x · Ax ∋x′)) = contradiction (∋-injective ∋x ∋x′)
|
||||
where
|
||||
contradiction : ∀ {A B} → ¬ (A ⇒ B ≡ A)
|
||||
|
@ -1185,15 +1180,15 @@ nope₂ (⊢ƛ (Ax ∋x · Ax ∋x′)) = contradiction (∋-injective ∋x
|
|||
For each of the following, given a type `A` for which it is derivable,
|
||||
or explain why there is no such `A`.
|
||||
|
||||
1. `` ∅ , "y" ⦂ `ℕ ⇒ `ℕ , "x" ⦂ `ℕ ⊢ ⌊ "y" ⌋ · ⌊ "x" ⌋ ⦂ A ``
|
||||
2. `` ∅ , "y" ⦂ `ℕ ⇒ `ℕ , "x" ⦂ `ℕ ⊢ ⌊ "x" ⌋ · ⌊ "y" ⌋ ⦂ A ``
|
||||
3. `` ∅ , "y" ⦂ `ℕ ⇒ `ℕ ⊢ ƛ "x" ⇒ ⌊ "y" ⌋ · ⌊ "x" ⌋ ⦂ A ``
|
||||
1. `` ∅ , "y" ⦂ `ℕ ⇒ `ℕ , "x" ⦂ `ℕ ⊢ ` "y" · ` "x" ⦂ A ``
|
||||
2. `` ∅ , "y" ⦂ `ℕ ⇒ `ℕ , "x" ⦂ `ℕ ⊢ ` "x" · ` "y" ⦂ A ``
|
||||
3. `` ∅ , "y" ⦂ `ℕ ⇒ `ℕ ⊢ ƛ "x" ⇒ ` "y" · ` "x" ⦂ A ``
|
||||
|
||||
For each of the following, give type `A`, `B`, and `C` for which it is derivable,
|
||||
or explain why there are no such types.
|
||||
|
||||
1. `` ∅ , "x" ⦂ A ⊢ ⌊ "x" ⌋ · ⌊ "x" ⌋ ⦂ B ``
|
||||
2. `` ∅ , "x" ⦂ A , "y" ⦂ B ⊢ ƛ "z" ⇒ ⌊ "x" ⌋ · (⌊ "y" ⌋ · ⌊ "z" ⌋) ⦂ C ``
|
||||
1. `` ∅ , "x" ⦂ A ⊢ ` "x" · ` "x" ⦂ B ``
|
||||
2. `` ∅ , "x" ⦂ A , "y" ⦂ B ⊢ ƛ "z" ⇒ ` "x" · (` "y" · ` "z") ⦂ C ``
|
||||
|
||||
|
||||
#### Exercise (`mul-type`)
|
||||
|
@ -1211,7 +1206,8 @@ This chapter uses the following unicode
|
|||
· U+00B7: MIDDLE DOT (\cdot)
|
||||
😇 U+1F607: SMILING FACE WITH HALO
|
||||
😈 U+1F608: SMILING FACE WITH HORNS
|
||||
⟶ U+27F9: LONG RIGHTWARDS ARROW (\r5, \-->)
|
||||
↦ U+21A6: RIGHTWARDS ARROW FROM BAR (\mapsto, \r-|)
|
||||
↠ U+21A0: RIGHTWARDS TWO HEADED ARROW (\rr-)
|
||||
ξ U+03BE: GREEK SMALL LETTER XI (\Gx or \xi)
|
||||
β U+03B2: GREEK SMALL LETTER BETA (\Gb or \beta)
|
||||
∋ U+220B: CONTAINS AS MEMBER (\ni)
|
||||
|
|
|
@ -15,7 +15,7 @@ Those parts will be revised.]
|
|||
The last chapter formalised simply-typed lambda calculus and
|
||||
introduced several important relations over it.
|
||||
We write `Value M` if term `M` is a value.
|
||||
We write `M ⟶ N` if term `M` reduces to term `N`.
|
||||
We write `M ↦ N` if term `M` reduces to term `N`.
|
||||
And we write `Γ ⊢ M ⦂ A` if in context `Γ` the term `M` has type `A`.
|
||||
We are particularly concerned with terms typed in the empty context
|
||||
`∅`, which must be _closed_ (that is, have no _free variables_).
|
||||
|
@ -40,7 +40,7 @@ a reduction step. As we will see, this property does _not_ hold for
|
|||
every term, but it does hold for every closed, well-typed term.
|
||||
|
||||
_Progress_: If `∅ ⊢ M ⦂ A` then either `M` is a value or there is an `N` such
|
||||
that `M ⟶ N`.
|
||||
that `M ↦ N`.
|
||||
|
||||
So, either we have a value, and we are done, or we can take a reduction step.
|
||||
In the latter case, we would like to apply progress again. But first we need
|
||||
|
@ -48,7 +48,7 @@ to know that the term yielded by the reduction is itself closed and well-typed.
|
|||
It turns out that this property holds whenever we start with a closed,
|
||||
well-typed term.
|
||||
|
||||
_Preservation_: If `∅ ⊢ M ⦂ A` and `M ⟶ N` then `∅ ⊢ N ⦂ A`.
|
||||
_Preservation_: If `∅ ⊢ M ⦂ A` and `M ↦ N` then `∅ ⊢ N ⦂ A`.
|
||||
|
||||
This gives us a recipe for evaluation. Start with a closed and well-typed term.
|
||||
By progress, it is either a value, in which case we are done, or it reduces
|
||||
|
@ -87,7 +87,6 @@ open import Relation.Nullary using (¬_; Dec; yes; no)
|
|||
open import Function using (_∘_)
|
||||
open import plta.Isomorphism
|
||||
open import plta.Lambda
|
||||
open Chain (Term) (_⟶_)
|
||||
\end{code}
|
||||
|
||||
|
||||
|
@ -192,7 +191,7 @@ second has a free variable. Every term that is well-typed and closed
|
|||
has the desired property.
|
||||
|
||||
_Progress_: If `∅ ⊢ M ⦂ A` then either `M` is a value or there is an `N` such
|
||||
that `M ⟶ N`.
|
||||
that `M ↦ N`.
|
||||
|
||||
To formulate this property, we first introduce a relation that
|
||||
captures what it means for a term `M` to make progess.
|
||||
|
@ -200,7 +199,7 @@ captures what it means for a term `M` to make progess.
|
|||
data Progress (M : Term) : Set where
|
||||
|
||||
step : ∀ {N}
|
||||
→ M ⟶ N
|
||||
→ M ↦ N
|
||||
----------
|
||||
→ Progress M
|
||||
|
||||
|
@ -210,7 +209,7 @@ data Progress (M : Term) : Set where
|
|||
→ Progress M
|
||||
\end{code}
|
||||
A term `M` makes progress if either it can take a step, meaning there
|
||||
exists a term `N` such that `M ⟶ N`, or if it is done, meaning that
|
||||
exists a term `N` such that `M ↦ N`, or if it is done, meaning that
|
||||
`M` is a value.
|
||||
|
||||
If a term is well-typed in the empty context then it is a value.
|
||||
|
@ -220,23 +219,23 @@ progress : ∀ {M A}
|
|||
----------
|
||||
→ Progress M
|
||||
progress (Ax ())
|
||||
progress (⊢ƛ ⊢N) = done V-ƛ
|
||||
progress (⊢ƛ ⊢N) = done V-ƛ
|
||||
progress (⊢L · ⊢M) with progress ⊢L
|
||||
... | step L⟶L′ = step (ξ-·₁ L⟶L′)
|
||||
... | step L↦L′ = step (ξ-·₁ L↦L′)
|
||||
... | done VL with progress ⊢M
|
||||
... | step M⟶M′ = step (ξ-·₂ VL M⟶M′)
|
||||
... | step M↦M′ = step (ξ-·₂ VL M↦M′)
|
||||
... | done VM with canonical ⊢L VL
|
||||
... | C-ƛ _ = step (β-ƛ· VM)
|
||||
progress ⊢zero = done V-zero
|
||||
... | C-ƛ _ = 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)
|
||||
... | 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′)
|
||||
... | step L↦L′ = step (ξ-case L↦L′)
|
||||
... | done VL with canonical ⊢L VL
|
||||
... | C-zero = step β-case-zero
|
||||
... | C-suc CL = step (β-case-suc (value CL))
|
||||
progress (⊢μ ⊢M) = step β-μ
|
||||
... | C-zero = step β-zero
|
||||
... | C-suc CL = step (β-suc (value CL))
|
||||
progress (⊢μ ⊢M) = step β-μ
|
||||
\end{code}
|
||||
We induct on the evidence that `M` is well-typed.
|
||||
Let's unpack the first three cases.
|
||||
|
@ -249,7 +248,7 @@ Let's unpack the first three cases.
|
|||
* If the term is an application `L · M`, recursively apply
|
||||
progress to the derivation that `L` is well-typed.
|
||||
|
||||
+ If the term steps, we have evidence that `L ⟶ L′`,
|
||||
+ If the term steps, we have evidence that `L ↦ L′`,
|
||||
which by `ξ-·₁` means that our original term steps
|
||||
to `L′ · M`
|
||||
|
||||
|
@ -257,7 +256,7 @@ Let's unpack the first three cases.
|
|||
a value. Recursively apply progress to the derivation
|
||||
that `M` is well-typed.
|
||||
|
||||
- If the term steps, we have evidence that `M ⟶ M′`,
|
||||
- If the term steps, we have evidence that `M ↦ M′`,
|
||||
which by `ξ-·₂` means that our original term steps
|
||||
to `L · M′`. Step `ξ-·₂` applies only if we have
|
||||
evidence that `L` is a value, but progress on that
|
||||
|
@ -269,7 +268,7 @@ Let's unpack the first three cases.
|
|||
since we are in an application leads to the
|
||||
conclusion that `L` must be a lambda
|
||||
abstraction. We also have evidence that `M` is
|
||||
a value, so our original term steps by `β-ƛ·`.
|
||||
a value, so our original term steps by `β-ƛ`.
|
||||
|
||||
The remaining cases are similar. If by induction we have a
|
||||
`step` case we apply a `ξ` rule, and if we have a `done` case
|
||||
|
@ -289,11 +288,11 @@ Instead of defining a data type for `Progress M`, we could
|
|||
have formulated progress using disjunction and existentials:
|
||||
\begin{code}
|
||||
postulate
|
||||
progress′ : ∀ M {A} → ∅ ⊢ M ⦂ A → Value M ⊎ ∃[ N ](M ⟶ N)
|
||||
progress′ : ∀ M {A} → ∅ ⊢ M ⦂ A → Value M ⊎ ∃[ N ](M ↦ N)
|
||||
\end{code}
|
||||
This leads to a less perspicous proof. Instead of the mnemonic `done`
|
||||
and `step` we use `inj₁` and `inj₂`, and the term `N` is no longer
|
||||
implicit and so must be written out in full. In the case for `β-ƛ·`
|
||||
implicit and so must be written out in full. In the case for `β-ƛ`
|
||||
this requires that we match against the lambda expression `L` to
|
||||
determine its bound variable and body, `ƛ x ⇒ N`, so we can show that
|
||||
`L · M` reduces to `N [ x := M ]`.
|
||||
|
@ -305,7 +304,7 @@ proof of `progress` above.
|
|||
|
||||
#### Exercise (`Progress-iso`)
|
||||
|
||||
Show that `Progress M` is isomorphic to `Value M ⊎ ∃[ N ](M ⟶ N)`.
|
||||
Show that `Progress M` is isomorphic to `Value M ⊎ ∃[ N ](M ↦ N)`.
|
||||
|
||||
|
||||
## Prelude to preservation
|
||||
|
@ -370,7 +369,7 @@ the same result as if we first substitute and then type the result.
|
|||
The third step is to show preservation.
|
||||
|
||||
_Preservation_:
|
||||
If `∅ ⊢ M ⦂ A` and `M ⟶ N` then `∅ ⊢ N ⦂ A`.
|
||||
If `∅ ⊢ M ⦂ A` and `M ↦ N` then `∅ ⊢ N ⦂ A`.
|
||||
|
||||
The proof is by induction over the possible reductions, and
|
||||
the substitution lemma is crucial in showing that each of the
|
||||
|
@ -404,7 +403,6 @@ ext : ∀ {Γ Δ}
|
|||
→ (∀ {x A} → Γ ∋ x ⦂ A → Δ ∋ x ⦂ A)
|
||||
-----------------------------------------------------
|
||||
→ (∀ {x y A B} → Γ , y ⦂ B ∋ x ⦂ A → Δ , y ⦂ B ∋ x ⦂ A)
|
||||
|
||||
ext ρ Z = Z
|
||||
ext ρ (S x≢y ∋x) = S x≢y (ρ ∋x)
|
||||
\end{code}
|
||||
|
@ -595,9 +593,9 @@ Now that naming is resolved, let's unpack the first three cases.
|
|||
* In the variable case, we must show
|
||||
|
||||
∅ ⊢ V ⦂ B
|
||||
Γ , y ⦂ B ⊢ ⌊ x ⌋ ⦂ A
|
||||
Γ , y ⦂ B ⊢ ` x ⦂ A
|
||||
------------------------
|
||||
Γ ⊢ ⌊ x ⌋ [ y := V ] ⦂ A
|
||||
Γ ⊢ ` x [ y := V ] ⦂ A
|
||||
|
||||
where the second hypothesis follows from:
|
||||
|
||||
|
@ -645,7 +643,7 @@ Now that naming is resolved, let's unpack the first three cases.
|
|||
x ≢ y
|
||||
Γ ∋ x ⦂ A
|
||||
-------------
|
||||
Γ ⊢ ⌊ x ⌋ ⦂ A
|
||||
Γ ⊢ ` x ⦂ A
|
||||
|
||||
which follows by the typing rule for variables.
|
||||
|
||||
|
@ -735,20 +733,20 @@ that reduction preserves types is straightforward.
|
|||
\begin{code}
|
||||
preserve : ∀ {M N A}
|
||||
→ ∅ ⊢ M ⦂ A
|
||||
→ M ⟶ N
|
||||
→ M ↦ N
|
||||
----------
|
||||
→ ∅ ⊢ N ⦂ A
|
||||
preserve (Ax ())
|
||||
preserve (⊢ƛ ⊢N) ()
|
||||
preserve (⊢L · ⊢M) (ξ-·₁ L⟶L′) = (preserve ⊢L L⟶L′) · ⊢M
|
||||
preserve (⊢L · ⊢M) (ξ-·₂ VL M⟶M′) = ⊢L · (preserve ⊢M M⟶M′)
|
||||
preserve ((⊢ƛ ⊢N) · ⊢V) (β-ƛ· VV) = subst ⊢V ⊢N
|
||||
preserve (⊢L · ⊢M) (ξ-·₁ L↦L′) = (preserve ⊢L L↦L′) · ⊢M
|
||||
preserve (⊢L · ⊢M) (ξ-·₂ VL M↦M′) = ⊢L · (preserve ⊢M M↦M′)
|
||||
preserve ((⊢ƛ ⊢N) · ⊢V) (β-ƛ VV) = subst ⊢V ⊢N
|
||||
preserve ⊢zero ()
|
||||
preserve (⊢suc ⊢M) (ξ-suc M⟶M′) = ⊢suc (preserve ⊢M M⟶M′)
|
||||
preserve (⊢case ⊢L ⊢M ⊢N) (ξ-case L⟶L′) = ⊢case (preserve ⊢L L⟶L′) ⊢M ⊢N
|
||||
preserve (⊢case ⊢zero ⊢M ⊢N) β-case-zero = ⊢M
|
||||
preserve (⊢case (⊢suc ⊢V) ⊢M ⊢N) (β-case-suc VV) = subst ⊢V ⊢N
|
||||
preserve (⊢μ ⊢M) (β-μ) = subst (⊢μ ⊢M) ⊢M
|
||||
preserve (⊢suc ⊢M) (ξ-suc M↦M′) = ⊢suc (preserve ⊢M M↦M′)
|
||||
preserve (⊢case ⊢L ⊢M ⊢N) (ξ-case L↦L′) = ⊢case (preserve ⊢L L↦L′) ⊢M ⊢N
|
||||
preserve (⊢case ⊢zero ⊢M ⊢N) β-zero = ⊢M
|
||||
preserve (⊢case (⊢suc ⊢V) ⊢M ⊢N) (β-suc VV) = subst ⊢V ⊢N
|
||||
preserve (⊢μ ⊢M) (β-μ) = subst (⊢μ ⊢M) ⊢M
|
||||
\end{code}
|
||||
The proof never mentions the types of `M` or `N`,
|
||||
so in what follows we choose type name as convenient.
|
||||
|
@ -757,9 +755,9 @@ Let's unpack the cases for two of the reduction rules.
|
|||
|
||||
* Rule `ξ-·₁`. We have
|
||||
|
||||
L ⟶ L′
|
||||
L ↦ L′
|
||||
----------------
|
||||
L · M ⟶ L′ · M
|
||||
L · M ↦ L′ · M
|
||||
|
||||
where the left-hand side is typed by
|
||||
|
||||
|
@ -771,13 +769,13 @@ Let's unpack the cases for two of the reduction rules.
|
|||
By induction, we have
|
||||
|
||||
Γ ⊢ L ⦂ A ⇒ B
|
||||
L ⟶ L′
|
||||
L ↦ L′
|
||||
--------------
|
||||
Γ ⊢ L′ ⦂ A ⇒ B
|
||||
|
||||
from which the typing of the right-hand side follows immediately.
|
||||
|
||||
* Rule `β-ƛ·`. We have
|
||||
* Rule `β-ƛ`. We have
|
||||
|
||||
Value V
|
||||
----------------------------
|
||||
|
@ -813,15 +811,17 @@ well-typed term to its value, if it has one.
|
|||
|
||||
Some terms may reduce forever. Here is a simple example.
|
||||
\begin{code}
|
||||
sucμ = μ "x" ⇒ `suc (` "x")
|
||||
|
||||
_ =
|
||||
begin
|
||||
μ "x" ⇒ `suc ⌊ "x" ⌋
|
||||
⟶⟨ β-μ ⟩
|
||||
`suc (μ "x" ⇒ `suc ⌊ "x" ⌋)
|
||||
⟶⟨ ξ-suc β-μ ⟩
|
||||
`suc `suc (μ "x" ⇒ `suc ⌊ "x" ⌋)
|
||||
⟶⟨ ξ-suc (ξ-suc β-μ) ⟩
|
||||
`suc `suc `suc (μ "x" ⇒ `suc ⌊ "x" ⌋)
|
||||
sucμ
|
||||
↦⟨ β-μ ⟩
|
||||
`suc sucμ
|
||||
↦⟨ ξ-suc β-μ ⟩
|
||||
`suc `suc sucμ
|
||||
↦⟨ ξ-suc (ξ-suc β-μ) ⟩
|
||||
`suc `suc `suc sucμ
|
||||
-- ...
|
||||
∎
|
||||
\end{code}
|
||||
|
@ -871,7 +871,7 @@ well-typed and an indication of whether reduction finished.
|
|||
data Steps (L : Term) (A : Type) : Set where
|
||||
|
||||
steps : ∀ {N}
|
||||
→ L ⟶* N
|
||||
→ L ↠ N
|
||||
→ ∅ ⊢ N ⦂ A
|
||||
→ Finished N
|
||||
----------
|
||||
|
@ -886,18 +886,18 @@ eval : ∀ {L A}
|
|||
→ ∅ ⊢ L ⦂ A
|
||||
---------
|
||||
→ Steps L A
|
||||
eval {L} (gas zero) ⊢L = steps (L ∎) ⊢L out-of-gas
|
||||
eval {L} (gas zero) ⊢L = steps (L ∎) ⊢L out-of-gas
|
||||
eval {L} (gas (suc m)) ⊢L with progress ⊢L
|
||||
... | done VL = steps (L ∎) ⊢L (done VL)
|
||||
... | step L⟶M with eval (gas m) (preserve ⊢L L⟶M)
|
||||
... | steps M⟶*N ⊢N fin = steps (L ⟶⟨ L⟶M ⟩ M⟶*N) ⊢N fin
|
||||
... | done VL = steps (L ∎) ⊢L (done VL)
|
||||
... | step L↦M with eval (gas m) (preserve ⊢L L↦M)
|
||||
... | steps M↠N ⊢N fin = steps (L ↦⟨ L↦M ⟩ M↠N) ⊢N fin
|
||||
\end{code}
|
||||
Let `L` be the name of the term we are reducing, and `⊢L` be the
|
||||
evidence that `L` is well-typed. We consider the amount of gas
|
||||
remaining. There are two possibilities.
|
||||
|
||||
* It is zero, so we stop early. We return the trivial reduction
|
||||
sequence `L ⟶* L`, evidence that `L` is well-typed, and an
|
||||
sequence `L ↠ L`, evidence that `L` is well-typed, and an
|
||||
indication that we are out of gas.
|
||||
|
||||
* It is non-zero and after the next step we have `m` gas remaining.
|
||||
|
@ -905,165 +905,187 @@ remaining. There are two possibilities.
|
|||
are two possibilities.
|
||||
|
||||
+ Term `L` is a value, so we are done. We return the
|
||||
trivial reduction sequence `L ⟶* L`, evidence that `L` is
|
||||
trivial reduction sequence `L ↠ L`, evidence that `L` is
|
||||
well-typed, and the evidence that `L` is a value.
|
||||
|
||||
+ Term `L` steps to another term `M`. Preservation provides
|
||||
evidence that `M` is also well-typed, and we recursively invoke
|
||||
`eval` on the remaining gas. The result is evidence that
|
||||
`M ⟶* N`, together with evidence that `N` is well-typed and an
|
||||
`M ↠ N`, together with evidence that `N` is well-typed and an
|
||||
indication of whether reduction finished. We combine the evidence
|
||||
that `L ⟶ M` and `M ⟶* N` to return evidence that `L ⟶* N`,
|
||||
that `L ↦ M` and `M ↠ N` to return evidence that `L ↠ N`,
|
||||
together with the other relevant evidence.
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
We can now use Agda to compute the reduction sequence for two plus two
|
||||
given in the preceding chapter.
|
||||
We can now use Agda to compute the non-terminating reduction
|
||||
sequence given earlier. First, we show that the term `sucμ`
|
||||
is well-typed.
|
||||
\begin{code}
|
||||
⊢sucμ : ∅ ⊢ μ "x" ⇒ `suc ` "x" ⦂ `ℕ
|
||||
⊢sucμ = ⊢μ (⊢suc (Ax ∋x))
|
||||
where
|
||||
∋x = Z
|
||||
\end{code}
|
||||
To show the first three steps of the infinite reduction
|
||||
sequence, we evaluate with three steps worth of gas.
|
||||
\begin{code}
|
||||
_ : eval (gas 3) ⊢sucμ ≡
|
||||
steps
|
||||
(μ "x" ⇒ `suc ` "x" ↦⟨ β-μ ⟩
|
||||
`suc (μ "x" ⇒ `suc ` "x") ↦⟨ ξ-suc β-μ ⟩
|
||||
`suc (`suc (μ "x" ⇒ `suc ` "x")) ↦⟨ ξ-suc (ξ-suc β-μ) ⟩
|
||||
`suc (`suc (`suc (μ "x" ⇒ `suc ` "x"))) ∎)
|
||||
(⊢suc (⊢suc (⊢suc (⊢μ (⊢suc (Ax Z)))))) out-of-gas
|
||||
_ = refl
|
||||
\end{code}
|
||||
|
||||
Similarly, we can use Agda to compute the reduction sequence for two plus two
|
||||
given in the preceding chapter. Supplying 100 steps of gas is more than enough.
|
||||
\begin{code}
|
||||
_ : eval (gas 100) ⊢four ≡
|
||||
steps
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· `suc (`suc `zero)
|
||||
· `suc (`suc `zero)
|
||||
⟶⟨ ξ-·₁ (ξ-·₁ β-μ) ⟩
|
||||
↦⟨ ξ-·₁ (ξ-·₁ β-μ) ⟩
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ⌊ "n" ⌋)
|
||||
· ` "m"
|
||||
· ` "n")
|
||||
]))
|
||||
· `suc (`suc `zero)
|
||||
· `suc (`suc `zero)
|
||||
⟶⟨ ξ-·₁ (β-ƛ· (V-suc (V-suc V-zero))) ⟩
|
||||
↦⟨ ξ-·₁ (β-ƛ (V-suc (V-suc V-zero))) ⟩
|
||||
(ƛ "n" ⇒
|
||||
`case `suc (`suc `zero) [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
|
||||
`case `suc (`suc `zero) [zero⇒ ` "n" |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ⌊ "n" ⌋)
|
||||
· ` "m"
|
||||
· ` "n")
|
||||
])
|
||||
· `suc (`suc `zero)
|
||||
⟶⟨ β-ƛ· (V-suc (V-suc V-zero)) ⟩
|
||||
↦⟨ β-ƛ (V-suc (V-suc V-zero)) ⟩
|
||||
`case `suc (`suc `zero) [zero⇒ `suc (`suc `zero) |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ` "m"
|
||||
· `suc (`suc `zero))
|
||||
]
|
||||
⟶⟨ β-case-suc (V-suc V-zero) ⟩
|
||||
↦⟨ β-suc (V-suc V-zero) ⟩
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· `suc `zero
|
||||
· `suc (`suc `zero))
|
||||
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₁ β-μ)) ⟩
|
||||
↦⟨ ξ-suc (ξ-·₁ (ξ-·₁ β-μ)) ⟩
|
||||
`suc
|
||||
((ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ⌊ "n" ⌋)
|
||||
· ` "m"
|
||||
· ` "n")
|
||||
]))
|
||||
· `suc `zero
|
||||
· `suc (`suc `zero))
|
||||
⟶⟨ ξ-suc (ξ-·₁ (β-ƛ· (V-suc V-zero))) ⟩
|
||||
↦⟨ ξ-suc (ξ-·₁ (β-ƛ (V-suc V-zero))) ⟩
|
||||
`suc
|
||||
((ƛ "n" ⇒
|
||||
`case `suc `zero [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
|
||||
`case `suc `zero [zero⇒ ` "n" |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ⌊ "n" ⌋)
|
||||
· ` "m"
|
||||
· ` "n")
|
||||
])
|
||||
· `suc (`suc `zero))
|
||||
⟶⟨ ξ-suc (β-ƛ· (V-suc (V-suc V-zero))) ⟩
|
||||
↦⟨ ξ-suc (β-ƛ (V-suc (V-suc V-zero))) ⟩
|
||||
`suc
|
||||
`case `suc `zero [zero⇒ `suc (`suc `zero) |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ` "m"
|
||||
· `suc (`suc `zero))
|
||||
]
|
||||
⟶⟨ ξ-suc (β-case-suc V-zero) ⟩
|
||||
↦⟨ ξ-suc (β-suc V-zero) ⟩
|
||||
`suc
|
||||
(`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· `zero
|
||||
· `suc (`suc `zero)))
|
||||
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ β-μ))) ⟩
|
||||
↦⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ β-μ))) ⟩
|
||||
`suc
|
||||
(`suc
|
||||
((ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ⌊ "n" ⌋)
|
||||
· ` "m"
|
||||
· ` "n")
|
||||
]))
|
||||
· `zero
|
||||
· `suc (`suc `zero)))
|
||||
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (β-ƛ· V-zero))) ⟩
|
||||
↦⟨ ξ-suc (ξ-suc (ξ-·₁ (β-ƛ V-zero))) ⟩
|
||||
`suc
|
||||
(`suc
|
||||
((ƛ "n" ⇒
|
||||
`case `zero [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
|
||||
`case `zero [zero⇒ ` "n" |suc "m" ⇒
|
||||
`suc
|
||||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ⌊ "n" ⌋)
|
||||
· ` "m"
|
||||
· ` "n")
|
||||
])
|
||||
· `suc (`suc `zero)))
|
||||
⟶⟨ ξ-suc (ξ-suc (β-ƛ· (V-suc (V-suc V-zero)))) ⟩
|
||||
↦⟨ ξ-suc (ξ-suc (β-ƛ (V-suc (V-suc V-zero)))) ⟩
|
||||
`suc
|
||||
(`suc
|
||||
`case `zero [zero⇒ `suc (`suc `zero) |suc "m" ⇒
|
||||
|
@ -1071,21 +1093,21 @@ _ : eval (gas 100) ⊢four ≡
|
|||
((μ "+" ⇒
|
||||
(ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
|
||||
`case ` "m" [zero⇒ ` "n" |suc "m" ⇒ `suc (` "+" · ` "m" · ` "n")
|
||||
])))
|
||||
· ⌊ "m" ⌋
|
||||
· ` "m"
|
||||
· `suc (`suc `zero))
|
||||
])
|
||||
⟶⟨ ξ-suc (ξ-suc β-case-zero) ⟩ `suc (`suc (`suc (`suc `zero))) ∎)
|
||||
↦⟨ ξ-suc (ξ-suc β-zero) ⟩ `suc (`suc (`suc (`suc `zero))) ∎)
|
||||
(⊢suc (⊢suc (⊢suc (⊢suc ⊢zero))))
|
||||
(done (V-suc (V-suc (V-suc (V-suc V-zero)))))
|
||||
_ = refl
|
||||
\end{code}
|
||||
The example above was generated by using ^C ^N to normalise the
|
||||
The example above was generated by using `C `N to normalise the
|
||||
left-hand side of the equation and pasting in the result as the
|
||||
right-hand side of the equation. The result was then edited to give
|
||||
the example reduction of the previous chapter, by writing `plus`
|
||||
and `two` in place of the corresponding terms and reformatting.
|
||||
right-hand side of the equation. The example reduction of the
|
||||
previous chapter was derived from this result, by writing `plus` and
|
||||
`two` in place of their corresponding expansions and reformatting.
|
||||
|
||||
Similarly, can evaluate the corresponding term for Church numerals.
|
||||
\begin{code}
|
||||
|
@ -1093,88 +1115,73 @@ _ : eval (gas 100) ⊢fourᶜ ≡
|
|||
steps
|
||||
((ƛ "m" ⇒
|
||||
(ƛ "n" ⇒
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)))))
|
||||
· (ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)))
|
||||
· (ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)))
|
||||
· (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ` "m" · ` "s" · (` "n" · ` "s" · ` "z")))))
|
||||
· (ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z")))
|
||||
· (ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z")))
|
||||
· (ƛ "n" ⇒ `suc ` "n")
|
||||
· `zero
|
||||
⟶⟨ ξ-·₁ (ξ-·₁ (ξ-·₁ (β-ƛ· V-ƛ))) ⟩
|
||||
↦⟨ ξ-·₁ (ξ-·₁ (ξ-·₁ (β-ƛ V-ƛ))) ⟩
|
||||
(ƛ "n" ⇒
|
||||
(ƛ "s" ⇒
|
||||
(ƛ "z" ⇒
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · ⌊ "s" ⌋ ·
|
||||
(⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋))))
|
||||
· (ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)))
|
||||
· (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · ` "s" ·
|
||||
(` "n" · ` "s" · ` "z"))))
|
||||
· (ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z")))
|
||||
· (ƛ "n" ⇒ `suc ` "n")
|
||||
· `zero
|
||||
⟶⟨ ξ-·₁ (ξ-·₁ (β-ƛ· V-ƛ)) ⟩
|
||||
↦⟨ ξ-·₁ (ξ-·₁ (β-ƛ V-ƛ)) ⟩
|
||||
(ƛ "s" ⇒
|
||||
(ƛ "z" ⇒
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · ⌊ "s" ⌋ ·
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · ⌊ "s" ⌋ · ⌊ "z" ⌋)))
|
||||
· (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · ` "s" ·
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · ` "s" · ` "z")))
|
||||
· (ƛ "n" ⇒ `suc ` "n")
|
||||
· `zero
|
||||
⟶⟨ ξ-·₁ (β-ƛ· V-ƛ) ⟩
|
||||
↦⟨ ξ-·₁ (β-ƛ V-ƛ) ⟩
|
||||
(ƛ "z" ⇒
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · (ƛ "n" ⇒ `suc ` "n")
|
||||
·
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
· ⌊ "z" ⌋))
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · (ƛ "n" ⇒ `suc ` "n")
|
||||
· ` "z"))
|
||||
· `zero
|
||||
⟶⟨ β-ƛ· V-zero ⟩
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
↦⟨ β-ƛ V-zero ⟩
|
||||
(ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · (ƛ "n" ⇒ `suc ` "n")
|
||||
·
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · (ƛ "n" ⇒ `suc ` "n")
|
||||
· `zero)
|
||||
⟶⟨ ξ-·₁ (β-ƛ· V-ƛ) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
|
||||
↦⟨ ξ-·₁ (β-ƛ V-ƛ) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · ` "z")) ·
|
||||
((ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · ` "z"))) · (ƛ "n" ⇒ `suc ` "n")
|
||||
· `zero)
|
||||
⟶⟨ ξ-·₂ V-ƛ (ξ-·₁ (β-ƛ· V-ƛ)) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
|
||||
((ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
|
||||
↦⟨ ξ-·₂ V-ƛ (ξ-·₁ (β-ƛ V-ƛ)) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · ` "z")) ·
|
||||
((ƛ "z" ⇒ (ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · ` "z")) ·
|
||||
`zero)
|
||||
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· V-zero) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
|
||||
((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `zero))
|
||||
⟶⟨ ξ-·₂ V-ƛ (ξ-·₂ V-ƛ (β-ƛ· V-zero)) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
|
||||
((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `suc `zero)
|
||||
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· (V-suc V-zero)) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
|
||||
↦⟨ ξ-·₂ V-ƛ (β-ƛ V-zero) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · ` "z")) ·
|
||||
((ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · `zero))
|
||||
↦⟨ ξ-·₂ V-ƛ (ξ-·₂ V-ƛ (β-ƛ V-zero)) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · ` "z")) ·
|
||||
((ƛ "n" ⇒ `suc ` "n") · `suc `zero)
|
||||
↦⟨ ξ-·₂ V-ƛ (β-ƛ (V-suc V-zero)) ⟩
|
||||
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · ` "z")) ·
|
||||
`suc (`suc `zero)
|
||||
⟶⟨ β-ƛ· (V-suc (V-suc V-zero)) ⟩
|
||||
(ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `suc (`suc `zero))
|
||||
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· (V-suc (V-suc V-zero))) ⟩
|
||||
(ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `suc (`suc (`suc `zero)) ⟶⟨
|
||||
β-ƛ· (V-suc (V-suc (V-suc V-zero))) ⟩
|
||||
↦⟨ β-ƛ (V-suc (V-suc V-zero)) ⟩
|
||||
(ƛ "n" ⇒ `suc ` "n") · ((ƛ "n" ⇒ `suc ` "n") · `suc (`suc `zero))
|
||||
↦⟨ ξ-·₂ V-ƛ (β-ƛ (V-suc (V-suc V-zero))) ⟩
|
||||
(ƛ "n" ⇒ `suc ` "n") · `suc (`suc (`suc `zero)) ↦⟨
|
||||
β-ƛ (V-suc (V-suc (V-suc V-zero))) ⟩
|
||||
`suc (`suc (`suc (`suc `zero))) ∎)
|
||||
(⊢suc (⊢suc (⊢suc (⊢suc ⊢zero))))
|
||||
(done (V-suc (V-suc (V-suc (V-suc V-zero)))))
|
||||
_ = refl
|
||||
\end{code}
|
||||
|
||||
We can also derive the non-terminating example.
|
||||
\begin{code}
|
||||
⊢sucμ : ∅ ⊢ μ "x" ⇒ `suc ⌊ "x" ⌋ ⦂ `ℕ
|
||||
⊢sucμ = ⊢μ (⊢suc (Ax ∋x))
|
||||
where
|
||||
∋x = Z
|
||||
|
||||
_ : eval (gas 3) ⊢sucμ ≡
|
||||
steps
|
||||
(μ "x" ⇒ `suc ⌊ "x" ⌋ Chain.⟶⟨ β-μ ⟩
|
||||
`suc (μ "x" ⇒ `suc ⌊ "x" ⌋) Chain.⟶⟨ ξ-suc β-μ ⟩
|
||||
`suc (`suc (μ "x" ⇒ `suc ⌊ "x" ⌋)) Chain.⟶⟨ ξ-suc (ξ-suc β-μ) ⟩
|
||||
`suc (`suc (`suc (μ "x" ⇒ `suc ⌊ "x" ⌋))) Chain.∎)
|
||||
(⊢suc (⊢suc (⊢suc (⊢μ (⊢suc (Ax Z)))))) out-of-gas
|
||||
_ = refl
|
||||
\end{code}
|
||||
Again, the example in the previous section was derived by editing the
|
||||
above.
|
||||
|
||||
#### Exercise `subject_expansion`
|
||||
|
||||
We say that `M` _reduces_ to `N` if `M ⟶ N`,
|
||||
and conversely that `M` _expands_ to `N` if `N ⟶ M`.
|
||||
We say that `M` _reduces_ to `N` if `M ↦ N`,
|
||||
and conversely that `M` _expands_ to `N` if `N ↦ M`.
|
||||
The preservation property is sometimes called _subject reduction_.
|
||||
Its opposite is _subject expansion_, which holds if
|
||||
`M ==> N` and `∅ ⊢ N ⦂ A` imply `∅ ⊢ M ⦂ A`.
|
||||
|
@ -1186,7 +1193,7 @@ with case expressions and one not involving case expressions.
|
|||
A term is _normal_ if it cannot reduce.
|
||||
\begin{code}
|
||||
Normal : Term → Set
|
||||
Normal M = ∀ {N} → ¬ (M ⟶ N)
|
||||
Normal M = ∀ {N} → ¬ (M ↦ N)
|
||||
\end{code}
|
||||
|
||||
A term is _stuck_ if it is normal yet not a value.
|
||||
|
@ -1200,7 +1207,7 @@ Using progress and preservation, it is easy to show that well-typed terms don't
|
|||
postulate
|
||||
wttdgs : ∀ {M N A}
|
||||
→ ∅ ⊢ M ⦂ A
|
||||
→ M ⟶* N
|
||||
→ M ↠ N
|
||||
-----------
|
||||
→ ¬ (Stuck M)
|
||||
\end{code}
|
||||
|
@ -1223,8 +1230,8 @@ unstuck : ∀ {M A}
|
|||
→ ∅ ⊢ M ⦂ A
|
||||
-----------
|
||||
→ ¬ (Stuck M)
|
||||
unstuck ⊢M ⟨ ¬M⟶N , ¬VM ⟩ with progress ⊢M
|
||||
... | step M⟶N = ¬M⟶N M⟶N
|
||||
unstuck ⊢M ⟨ ¬M↦N , ¬VM ⟩ with progress ⊢M
|
||||
... | step M↦N = ¬M↦N M↦N
|
||||
... | done VM = ¬VM VM
|
||||
\end{code}
|
||||
|
||||
|
@ -1232,21 +1239,21 @@ Any descendant of a well-typed term is well-typed.
|
|||
\begin{code}
|
||||
preserve* : ∀ {M N A}
|
||||
→ ∅ ⊢ M ⦂ A
|
||||
→ M ⟶* N
|
||||
→ M ↠ N
|
||||
---------
|
||||
→ ∅ ⊢ N ⦂ A
|
||||
preserve* ⊢M (M ∎) = ⊢M
|
||||
preserve* ⊢L (L ⟶⟨ L⟶M ⟩ M⟶*N) = preserve* (preserve ⊢L L⟶M) M⟶*N
|
||||
preserve* ⊢L (L ↦⟨ L↦M ⟩ M↠N) = preserve* (preserve ⊢L L↦M) M↠N
|
||||
\end{code}
|
||||
|
||||
Combining the above gives us the desired result.
|
||||
\begin{code}
|
||||
wttdgs′ : ∀ {M N A}
|
||||
→ ∅ ⊢ M ⦂ A
|
||||
→ M ⟶* N
|
||||
→ M ↠ N
|
||||
-----------
|
||||
→ ¬ (Stuck N)
|
||||
wttdgs′ ⊢M M⟶*N = unstuck (preserve* ⊢M M⟶*N)
|
||||
wttdgs′ ⊢M M↠N = unstuck (preserve* ⊢M M↠N)
|
||||
\end{code}
|
||||
|
||||
|
||||
|
@ -1261,7 +1268,7 @@ and preservation theorems for the simply typed lambda-calculus.
|
|||
Suppose we add a new term `zap` with the following reduction rule
|
||||
|
||||
--------- β-zap
|
||||
M ⟶ zap
|
||||
M ↦ zap
|
||||
|
||||
and the following typing rule:
|
||||
|
||||
|
@ -1286,10 +1293,10 @@ Suppose instead that we add a new term `foo` with the following
|
|||
reduction rules:
|
||||
|
||||
--------------------- β-foo₁
|
||||
(λ x ⇒ ⌊ x ⌋) ⟶ foo
|
||||
(λ x ⇒ ` x) ↦ foo
|
||||
|
||||
------------ β-foo₂
|
||||
foo ⟶ zero
|
||||
foo ↦ zero
|
||||
|
||||
Which of the following properties remain true in
|
||||
the presence of this rule? For each one, write either
|
||||
|
@ -1305,7 +1312,7 @@ false, give a counterexample.
|
|||
|
||||
#### Quiz
|
||||
|
||||
Suppose instead that we remove the rule `ξ·₁` from the `⟶`
|
||||
Suppose instead that we remove the rule `ξ·₁` from the step
|
||||
relation. Which of the following properties remain
|
||||
true in the absence of this rule? For each one, write either
|
||||
"remains true" or else "becomes false." If a property becomes
|
||||
|
|
Loading…
Reference in a new issue