starting on Inference

This commit is contained in:
wadler 2018-05-17 19:59:21 -03:00
parent a7552e1a19
commit f0d0db6d57
3 changed files with 970 additions and 0 deletions

269
src/Inference.lagda Normal file
View file

@ -0,0 +1,269 @@
---
title : "Inference: Bidirectional type inference"
layout : page
permalink : /Inference
---
Given Raw terms and inherently typed terms, specify
an algorithm going from one to the other.
There are *many* ways to do this. Which is best?
First dimension: staged/direct
* Staged: Raw -> Scoped, Scoped -> Typed
* Direct: Raw -> Typed in one fell swoop
Second dimension: derivation/function
* Derviation: Type derivations similar to usual rules, erasure of typing to Typed
* Function: Function to compute Typed term directly
Let's fiddle about with a couple of these to see which is best.
The Agda manual gives a solution for Staged/Function (second half of staged).
I'm quite keen to try Direct/Derivation.
## Imports
\begin{code}
module Inference where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; map; foldr; filter; length)
open import Data.Nat using (; zero; suc; _+_)
open import Data.String using (String; _≟_; _++_)
open import Data.Product
using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Collections
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
## Identifiers
\begin{code}
Id : Set
Id = String
\end{code}
### Lists of identifiers
\begin{code}
open Collections (Id) (_≟_)
\end{code}
## First development: Raw
\begin{code}
module Raw where
\end{code}
### Syntax
\begin{code}
infix 4 _∋_`:_
infix 4 _⊢_↑_
infix 4 _⊢_↓_
infixl 5 _,_`:_
infix 5 _`:_
infixr 6 _`→_
infix 6 `λ_`→_
infix 6 `μ_`→_
infixl 9 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_`:_ : Ctx → Id → Type → Ctx
data Term : Set where
⌊_⌋ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc : Term → Term
`case_[`zero`→_|`suc_`→_] : Term → Term → Id → Term → Term
`μ_`→_ : Id → Term → Term
_`:_ : Term → Type → Term
\end{code}
### Example terms
\begin{code}
Ch : Type
Ch = (` `→ `) `→ ` `→ `
two : Term
two = (`λ "s" `→ `λ "z" `→ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)) `: Ch
plus : Term
plus = (`λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋))
`: Ch `→ Ch `→ Ch
norm : Term
norm = (`λ "m" `→ ⌊ "m" ⌋ · (`λ "x" `→ `suc ⌊ "x" ⌋) · `zero)
`: Ch `→ `
four : Term
four = norm · (plus · two · two)
\end{code}
### Bidirectional type checking
\begin{code}
data _∋_`:_ : Ctx → Id → Type → Set where
Z : ∀ {Γ x A}
--------------------
→ Γ , x `: A ∋ x `: A
S : ∀ {Γ w x A B}
→ w ≢ x
→ Γ ∋ w `: B
--------------------
→ Γ , x `: A ∋ w `: B
data _⊢_↑_ : Ctx → Term → Type → Set
data _⊢_↓_ : Ctx → Term → Type → Set
data _⊢_↑_ where
Ax : ∀ {Γ A x}
→ Γ ∋ x `: A
--------------
→ Γ ⊢ ⌊ x ⌋ ↑ A
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L ↑ A `→ B
→ Γ ⊢ M ↑ A
---------------
→ Γ ⊢ L · M ↑ B
↑↓ : ∀ {Γ M A}
→ Γ ⊢ M ↓ A
----------------
→ Γ ⊢ M `: A ↑ A
data _⊢_↓_ where
⊢λ : ∀ {Γ x N A B}
→ Γ , x `: A ⊢ N ↓ B
-----------------------
→ Γ ⊢ `λ x `→ N ↓ A `→ B
⊢zero : ∀ {Γ}
---------------
→ Γ ⊢ `zero ↓ `
⊢suc : ∀ {Γ M}
→ Γ ⊢ M ↓ `
----------------
→ Γ ⊢ `suc M ↓ `
⊢case : ∀ {Γ L M x N A}
→ Γ ⊢ L ↑ `
→ Γ ⊢ M ↓ A
→ Γ , x `: A ⊢ N ↓ A
------------------------------------------
→ Γ ⊢ `case L [`zero`→ M |`suc x `→ N ] ↓ A
⊢μ : ∀ {Γ x N A}
→ Γ , x `: A ⊢ N ↓ A
-----------------------
→ Γ ⊢ `μ x `→ N ↓ A `→ A
↓↑ : ∀ {Γ M A}
→ Γ ⊢ M ↑ A
----------
→ Γ ⊢ M ↓ A
\end{code}
## Type checking monad
\begin{code}
Error : Set
Error = String
TC : Set → Set
TC A = Error ⊎ A
error : ∀ {A : Set} → Error → TC A
error = inj₁
return : ∀ {A : Set} → A → TC A
return = inj₂
_>>=_ : ∀ {A B : Set} → TC A → (A → TC B) → TC B
inj₁ e >>= k = inj₁ e
inj₂ x >>= k = k x
\end{code}
## Type inferencer
\begin{code}
_≟Tp_ : (A B : Type) → Dec (A ≡ B)
A ≟Tp B = {!!}
show : Type → String
show A = {!!}
data Lookup (Γ : Ctx) (x : Id) : Set where
ok : ∀ (A : Type) → (Γ ∋ x `: A) → Lookup Γ x
lookup : ∀ (Γ : Ctx) (x : Id) → TC (Lookup Γ x)
lookup ε x =
error ("variable " ++ x ++ " not bound")
lookup (Γ , x `: A) w with w ≟ x
... | yes refl =
return (ok A Z)
... | no w≢ =
do ok A ⊢x ← lookup Γ w
return (ok A (S w≢ ⊢x))
data Synth (Γ : Ctx) (M : Term) : Set where
ok : ∀ (A : Type) → (Γ ⊢ M ↑ A) → Synth Γ M
synth : ∀ (Γ : Ctx) (M : Term) → TC (Synth Γ M)
inher : ∀ (Γ : Ctx) (M : Term) (A : Type) → TC (Γ ⊢ M ↓ A)
synth Γ ⌊ x ⌋ =
do ok A ⊢x ← lookup Γ x
return (ok A (Ax ⊢x))
synth Γ (L · M) =
do ok (A₀ `→ B) ⊢L ← synth Γ L
where _ → error "application of non-function"
ok A₁ ⊢M ← synth Γ M
yes refl ← return (A₀ ≟Tp A₁)
where no _ → error "types differ in application"
return (ok B (⊢L · ⊢M))
synth Γ (M `: A) =
do ⊢M ← inher Γ M A
return (ok A (↑↓ ⊢M))
synth Γ M =
error "untypable term"
inher Γ M A = {!!}
\end{code}

View file

@ -247,6 +247,20 @@ data _⟶_ : ∀ {Γ A} → (Γ ⊢ A) → (Γ ⊢ A) → Set where
→ μ N ⟶ N [ μ N ]
\end{code}
Two possible formulations of `μ`
μ f → N ⟶ N [ f := μ f → N ]
(μ f → λ x → N) · V ⟶ N [ f := μ f → λ x → N , x := V ]
The first is odd in that we substitute for `f` a term that is not a value.
The second has two values of function type, both lambda abstractions and fixpoints.
## Reflexive and transitive closure
\begin{code}

View file

@ -0,0 +1,687 @@
---
title : "Raw: Raw, Scoped, Typed"
layout : page
permalink : /Raw
---
This version uses raw terms.
The substitution algorithm is based on one by McBride.
## Imports
\begin{code}
module Raw where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter; length)
open import Data.Nat using (; zero; suc; _+_)
import Data.String as String
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
-- open import Data.Sum using (_⊎_; inj₁; inj₂)
-- open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Collections
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
## Identifiers
\begin{code}
Id : Set
Id = String
\end{code}
### Fresh variables
\begin{code}
fresh : List Id → Id → Id
fresh xs₀ y = helper xs₀ (length xs₀) y
where
prime : Id → Id
prime x = x String.++ ""
helper : List Id → → Id → Id
helper [] _ w = w
helper (x ∷ xs) n w with w ≟ x
helper (x ∷ xs) n w | no _ = helper xs n w
helper (x ∷ xs) (suc n) w | yes refl = helper xs₀ n (prime w)
helper (x ∷ xs) zero w | yes refl = ⊥-elim impossible
where postulate impossible : ⊥
\end{code}
### Lists of identifiers
\begin{code}
open Collections (Id) (_≟_)
\end{code}
## First development: Raw
\begin{code}
module Raw where
\end{code}
### Syntax
\begin{code}
infix 6 `λ_`→_
infixl 9 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_`:_ : Ctx → Id → Type → Ctx
data Term : Set where
⌊_⌋ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc : Term → Term
\end{code}
### Example terms
\begin{code}
two : Term
two = `λ "s" `→ `λ "z" `→ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)
plus : Term
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)
norm : Term
norm = `λ "m" `→ ⌊ "m" ⌋ · (`λ "x" `→ `suc ⌊ "x" ⌋) · `zero
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (⌊ x ⌋) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ⌊ x ⌋
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Fresh variables
### Substitution
\begin{code}
subst : List Id → (Id → Term) → Term → Term
subst ys ρ ⌊ x ⌋ = ρ x
subst ys ρ (`λ x `→ N) = `λ y `→ subst (y ∷ ys) (ρ , x ↦ ⌊ y ⌋) N
where
y = fresh ys x
subst ys ρ (L · M) = subst ys ρ L · subst ys ρ M
subst ys ρ (`zero) = `zero
subst ys ρ (`suc M) = `suc (subst ys ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (free M ++ (free N \\ x)) (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : fresh [ "y" ] "y" ≡ "y"
_ = refl
_ : fresh [ "z" ] "y" ≡ "y"
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "z" := `zero ] ≡ (⌊ "s" ⌋ · ⌊ "s" ⌋ · `zero)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "z" ⌋ ] ≡ (`λ "y" `→ ⌊ "z" ⌋)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "y" ⌋ ] ≡ (`λ "y" `→ ⌊ "y" ⌋)
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "s" := (`λ "m" `→ `suc ⌊ "m" ⌋) ]
[ "z" := `zero ]
≡ (`λ "m" `→ `suc ⌊ "m" ⌋) · (`λ "m" `→ `suc ⌊ "m" ⌋) · `zero
_ = refl
_ : subst [] (∅ , "m" ↦ two , "n" ↦ `zero) (⌊ "m" ⌋ · ⌊ "n" ⌋) ≡ (two · `zero)
_ = refl
\end{code}
### Values
\begin{code}
data Natural : Term → Set where
Zero :
--------------
Natural `zero
Suc : ∀ {V}
→ Natural V
-----------------
→ Natural (`suc V)
data Value : Term → Set where
Nat : ∀ {V}
→ Natural V
----------
→ Value V
Fun : ∀ {x N}
-----------------
→ Value (`λ x `→ N)
\end{code}
### Decide whether a term is a value
Not needed, and no longer correct.
\begin{code}
{-
value : ∀ (M : Term) → Dec (Value M)
value ⌊ x ⌋ = no (λ())
value (`λ x `→ N) = yes Fun
value (L · M) = no (λ())
value `zero = yes Zero
value (`suc M) with value M
... | yes VM = yes (Suc VM)
... | no ¬VM = no (λ{(Suc VM) → (¬VM VM)})
-}
\end{code}
### Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
----------------
→ V · M ⟶ V · M
β-→ : ∀ {x N V}
→ Value V
--------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
------------------
→ `suc M ⟶ `suc M
\end{code}
### Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
### Decide whether a term reduces
\begin{code}
{-
data Step (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-------
→ Step M
reduce : ∀ (M : Term) → Dec (Step M)
reduce ⌊ x ⌋ = no (λ{(step ())})
reduce (`λ x `→ N) = no (λ{(step ())})
reduce (L · M) with reduce L
... | yes (step L⟶L) = yes (step (ξ-·₁ L⟶L))
... | no ¬L⟶L with value L
... | no ¬VL = no (λ{ (step (β-→ _)) → (¬VL Fun)
; (step (ξ-·₁ L⟶L)) → (¬L⟶L (step L⟶L))
; (step (ξ-·₂ VL _)) → (¬VL VL) })
... | yes VL with reduce M
... | yes (step M⟶M) = yes (step (ξ-·₂ VL M⟶M))
... | no ¬M⟶M = {!!}
reduce `zero = {!!}
reduce (`suc M) = {!!}
-}
\end{code}
### Stuck terms
\begin{code}
data Stuck : Term → Set where
st-·₁ : ∀ {L M}
→ Stuck L
--------------
→ Stuck (L · M)
st-·₂ : ∀ {V M}
→ Value V
→ Stuck M
--------------
→ Stuck (V · M)
st-·-nat : ∀ {V M}
→ Natural V
--------------
→ Stuck (V · M)
st-suc-λ : ∀ {x N}
-------------------------
→ Stuck (`suc (`λ x `→ N))
st-suc : ∀ {M}
→ Stuck M
--------------
→ Stuck (`suc M)
\end{code}
### Closed terms
\begin{code}
Closed : Term → Set
Closed M = free M ≡ []
Ax-lemma : ∀ {x} → ¬ (Closed ⌊ x ⌋)
Ax-lemma ()
closed-·₁ : ∀ {L M} → Closed (L · M) → Closed L
closed-·₁ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → xs ≡ []
lemma {xs = []} _ = refl
lemma {xs = x ∷ xs} ()
closed-·₂ : ∀ {L M} → Closed (L · M) → Closed M
closed-·₂ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → ys ≡ []
lemma {xs = []} refl = refl
lemma {xs = x ∷ xs} ()
·-closed : ∀ {L M} → Closed L → Closed M → Closed (L · M)
·-closed r s = lemma r s
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ≡ [] → ys ≡ [] → xs ++ ys ≡ []
lemma refl refl = refl
closed-suc : ∀ {M} → Closed (`suc M) → Closed M
closed-suc r = r
suc-closed : ∀ {M} → Closed M → Closed (`suc M)
suc-closed r = r
\end{code}
### Progress
\begin{code}
data Progress (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-----------
→ Progress M
stuck :
Stuck M
-----------
→ Progress M
done :
Value M
-----------
→ Progress M
\end{code}
### Progress
\begin{code}
progress : ∀ (M : Term) → Closed M → Progress M
progress ⌊ x ⌋ Cx = ⊥-elim (Ax-lemma Cx)
progress (L · M) CLM with progress L (closed-·₁ {L} {M} CLM)
... | step L⟶L = step (ξ-·₁ L⟶L)
... | stuck SL = stuck (st-·₁ SL)
... | done VL with progress M (closed-·₂ {L} {M} CLM)
... | step M⟶M = step (ξ-·₂ VL M⟶M)
... | stuck SM = stuck (st-·₂ VL SM)
... | done VM with VL
... | Nat NL = stuck (st-·-nat NL)
... | Fun = step (β-→ VM)
progress (`λ x `→ N) CxN = done Fun
progress `zero Cz = done (Nat Zero)
progress (`suc M) CsM with progress M (closed-suc {M} CsM)
... | step M⟶M = step (ξ-suc M⟶M)
... | stuck SM = stuck (st-suc SM)
... | done (Nat NL) = done (Nat (Suc NL))
... | done Fun = stuck st-suc-λ
\end{code}
### Preservation
Preservation of closed terms is not so easy.
\begin{code}
preservation : ∀ {M N : Term} → Closed M → M ⟶ N → Closed N
preservation = {!!}
{-
preservation CLM (ξ-·₁ L⟶L)
= ·-closed (preservation (closed-·₁ CLM) L⟶L) (closed-·₂ CLM)
preservation CLM (ξ-·₂ _ M⟶M)
= ·-closed (closed-·₁ CLM) (preservation (closed-·₂ CLM) M⟶M)
preservation CM (β-→ VM) = {!!} -- requires closure under substitution!
preservation CM (ξ-suc M⟶M)
= suc-closed (preservation (closed-suc CM) M⟶M)
-}
\end{code}
### Evaluation
\begin{code}
Gas : Set
Gas =
data Eval (M : Term) : Set where
out-of-gas : ∀ {N} → M ⟶* N → Eval M
stuck : ∀ {N} → M ⟶* N → Stuck N → Eval M
done : ∀ {V} → M ⟶* V → Value V → Eval M
eval : Gas → (L : Term) → Closed L → Eval L
eval zero L CL = out-of-gas (L ∎)
eval (suc n) L CL with progress L CL
... | stuck SL = stuck (L ∎) SL
... | done VL = done (L ∎) VL
... | step {M} L⟶M with eval n M (preservation CL L⟶M)
... | out-of-gas M⟶*N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N)
... | stuck M⟶*N SN = stuck (L ⟶⟨ L⟶M ⟩ M⟶*N) SN
... | done M⟶*V VV = done (L ⟶⟨ L⟶M ⟩ M⟶*V) VV
\end{code}
## Second development: Scoped
\begin{code}
module Scoped where
\end{code}
### Syntax
\begin{code}
infix 4 _⊢*
infix 4 _∋*
infixl 5 _,*
infix 5 `λ_`→_
infixl 6 _·_
data Ctx : Set where
ε : Ctx
_,* : Ctx → Ctx
data _∋* : Ctx → Set where
Z : ∀ {Γ}
------------
→ Γ ,* ∋*
S : ∀ {Γ}
→ Γ ∋*
--------
→ Γ ,* ∋*
data _⊢* : Ctx → Set where
⌊_⌋ : ∀ {Γ}
→ Γ ∋*
-----
→ Γ ⊢*
`λ_`→_ : ∀ {Γ} (x : Id)
→ Γ ,* ⊢*
--------
→ Γ ⊢*
_·_ : ∀ {Γ}
→ Γ ⊢*
→ Γ ⊢*
-----
→ Γ ⊢*
`zero : ∀ {Γ}
-----
→ Γ ⊢*
`suc : ∀ {Γ}
→ Γ ⊢*
-----
→ Γ ⊢*
\end{code}
### Shorthand for variables
\begin{code}
short : ∀{Γ} → → Γ ∋*
short {ε} n = ⊥-elim impossible
where postulate impossible : ⊥
short {Γ ,*} zero = Z
short {Γ ,*} (suc n) = S (short {Γ} n)
⌈_⌉ : ∀{Γ} → → Γ ⊢*
⌈ n ⌉ = ⌊ short n ⌋
\end{code}
### Sample terms
\begin{code}
two : ∀{Γ} → Γ ⊢*
two = `λ "s" `→ `λ "z" `→ ⌈ 1 ⌉ · (⌈ 1 ⌉ · ⌈ 0 ⌉)
plus : ∀{Γ} → Γ ⊢*
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌈ 3 ⌉ · ⌈ 1 ⌉ · (⌈ 2 ⌉ · ⌈ 1 ⌉ · ⌈ 0 ⌉)
norm : ∀{Γ} → Γ ⊢*
norm = `λ "m" `→ ⌈ 0 ⌉ · (`λ "x" `→ `suc ⌈ 0 ⌉) · `zero
\end{code}
### Conversion: Raw to Scoped
Doing the conversion from Raw to Scoped is hard.
The conversion takes a list of variables, with the invariant
is that every free variable in the term appears in this list.
But ensuring that the invariant holds is difficult.
One way around this may be *not* to ensure the invariant,
and to return `impossible` if it is violated. If the
conversion succeeds, it is guaranteed to return a term of
the correct type.
\begin{code}
raw→scoped : Raw.Term → ε ⊢*
raw→scoped M = helper [] M
where
lookup : List Id → Id →
lookup [] w = ⊥-elim impossible
where postulate impossible : ⊥
lookup (x ∷ xs) w with w ≟ x
... | yes _ = 0
... | no _ = suc (lookup xs w)
helper : ∀ {Γ} → List Id → Raw.Term → Γ ⊢*
helper xs Raw.⌊ x ⌋ = ⌈ lookup xs x ⌉
helper xs (Raw.`λ x `→ N) = `λ x `→ helper (x ∷ xs) N
helper xs (L Raw.· M) = helper xs L · helper xs M
helper xs Raw.`zero = `zero
helper xs (Raw.`suc M) = `suc (helper xs M)
\end{code}
### Test cases
\begin{code}
_ : raw→scoped Raw.two ≡ two
_ = refl
_ : raw→scoped Raw.plus ≡ plus
_ = refl
_ : raw→scoped Raw.norm ≡ norm
_ = refl
\end{code}
### Conversion: Scoped to Raw
\begin{code}
scoped→raw : ε ⊢* → Raw.Term
scoped→raw M = helper [] M
where
index : ∀ {Γ} → List Id → Γ ∋* → Id
index [] w = ⊥-elim impossible
where postulate impossible : ⊥
index (x ∷ xs) Z = x
index (x ∷ xs) (S w) = index xs w
helper : ∀ {Γ} → List Id → Γ ⊢* → Raw.Term
helper xs ⌊ x ⌋ = Raw.⌊ index xs x ⌋
helper xs (`λ x `→ N) = Raw.`λ y `→ helper (y ∷ xs) N
where y = fresh xs x
helper xs (L · M) = (helper xs L) Raw.· (helper xs M)
helper xs `zero = Raw.`zero
helper xs (`suc M) = Raw.`suc (helper xs M)
\end{code}
This is all straightforward. But what I would like to do is show that
meaning is preserved (or reductions are preserved) by the translations,
and that would be harder. I'm especially concerned by how one would
show the call to fresh is needed, or what goes wrong if it is omitted.
### Test cases
\begin{code}
_ : scoped→raw two ≡ Raw.two
_ = refl
_ : scoped→raw plus ≡ Raw.plus
_ = refl
_ : scoped→raw norm ≡ Raw.norm
_ = refl
_ : scoped→raw (`λ "x" `→ `λ "x" `→ ⌈ 1 ⌉ · ⌈ 0 ⌉) ≡
Raw.`λ "x" `→ Raw.`λ "x" `→ Raw.⌊ "x" ⌋ Raw.· Raw.⌊ "x" ⌋
_ = refl
\end{code}
## Third development: Typed
\begin{code}
module Typed where
infix 4 _⊢_
infix 4 _∋_
infixl 5 _,_
infixr 5 _`→_
infix 5 `λ_`→_
infixl 6 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_ : Ctx → Type → Ctx
data _∋_ : Ctx → Type → Set where
Z : ∀ {Γ A}
----------
→ Γ , A ∋ A
S : ∀ {Γ A B}
→ Γ ∋ B
---------
→ Γ , A ∋ B
data _⊢_ : Ctx → Type → Set where
⌊_⌋ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
`λ_`→_ : ∀ {Γ A B} (x : Id)
→ Γ , A ⊢ B
-----------
→ Γ ⊢ A `→ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A `→ B
→ Γ ⊢ A
-----------
→ Γ ⊢ B
`zero : ∀ {Γ}
----------
→ Γ ⊢ `
`suc : ∀ {Γ}
→ Γ ⊢ `
-------
→ Γ ⊢ `
\end{code}