csci8980-f21/extra/842Inference.agda
2020-05-22 15:50:50 +01:00

576 lines
16 KiB
Agda
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module 842Inference where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (; zero; suc; _+_)
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Relation.Nullary using (¬_; Dec; yes; no)
import plfa.part2.DeBruijn as DB
-- Syntax.
infix 4 _∋_⦂_
infix 4 _⊢_↑_
infix 4 _⊢_↓_
infixl 5 _,_⦂_
infixr 7 _⇒_
infix 5 ƛ_⇒_
infix 5 μ_⇒_
infix 6 _↑
infix 6 _↓_
infixl 7 _·_
infix 8 `suc_
infix 9 `_
Id : Set
Id = String
data Type : Set where
` : Type
_⇒_ : Type Type Type
data Context : Set where
: Context
_,_⦂_ : Context Id Type Context
data Term⁺ : Set
data Term⁻ : Set
data Term⁺ where
`_ : Id Term⁺
_·_ : Term⁺ Term⁻ Term⁺
_↓_ : Term⁻ Type Term⁺
data Term⁻ where
ƛ_⇒_ : Id Term⁻ Term⁻
`zero : Term⁻
`suc_ : Term⁻ Term⁻
`case_[zero⇒_|suc_⇒_] : Term⁺ Term⁻ Id Term⁻ Term⁻
μ_⇒_ : Id Term⁻ Term⁻
_↑ : Term⁺ Term⁻
-- Examples of terms.
two : Term⁻
two = `suc (`suc `zero)
plus : Term⁺
plus = (μ "p" ƛ "m" ƛ "n"
`case (` "m") [zero⇒ ` "n"
|suc "m" `suc (` "p" · (` "m" ) · (` "n" ) ) ])
(` ` `)
2+2 : Term⁺
2+2 = plus · two · two
Ch : Type
Ch = (` `) ` `
twoᶜ : Term⁻
twoᶜ = (ƛ "s" ƛ "z" ` "s" · (` "s" · (` "z" ) ) )
plusᶜ : Term⁺
plusᶜ = (ƛ "m" ƛ "n" ƛ "s" ƛ "z"
` "m" · (` "s" ) · (` "n" · (` "s" ) · (` "z" ) ) )
(Ch Ch Ch)
sucᶜ : Term⁻
sucᶜ = ƛ "x" `suc (` "x" )
2+2ᶜ : Term⁺
2+2ᶜ = plusᶜ · twoᶜ · twoᶜ · sucᶜ · `zero
-- Lookup judgments.
data _∋_⦂_ : Context Id Type Set where
Z : {Γ x A}
--------------------
Γ , x A x A
S : {Γ x y A B}
x y
Γ x A
-----------------
Γ , y B x A
-- Synthesis and inheritance.
data _⊢_↑_ : Context Term⁺ Type Set
data _⊢_↓_ : Context Term⁻ Type Set
data _⊢_↑_ where
⊢` : {Γ 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 ` N A
-------------------------------------
Γ `case L [zero⇒ M |suc x N ] A
⊢μ : {Γ x N A}
Γ , x A N A
-----------------
Γ μ x N A
⊢↑ : {Γ M A B}
Γ M A
A B
-------------
Γ (M ) B
-- PLFA exercise: write the term for multiplication (from Lambda)
-- PLFA exercise: extend the rules to support products (from More)
-- PLFA exercise (stretch): extend the rules to support the other
-- constructs from More
-- Equality of types.
_≟Tp_ : (A B : Type) Dec (A B)
` ≟Tp ` = yes refl
` ≟Tp (A B) = no λ()
(A B) ≟Tp ` = no λ()
(A B) ≟Tp (A B)
with A ≟Tp A | B ≟Tp B
... | no A≢ | _ = no λ{refl A≢ refl}
... | yes _ | no B≢ = no λ{refl B≢ refl}
... | yes refl | yes refl = yes refl
-- Helpers: domain and range of equal function types are equal,
-- ` is not a function type.
dom≡ : {A A B B} A B A B A A
dom≡ refl = refl
rng≡ : {A A B B} A B A B B B
rng≡ refl = refl
ℕ≢⇒ : {A B} ` A B
ℕ≢⇒ ()
-- Lookup judgments are unique.
uniq-∋ : {Γ x A B} Γ x A Γ x B A B
uniq-∋ Z Z = refl
uniq-∋ Z (S x≢y _) = ⊥-elim (x≢y refl)
uniq-∋ (S x≢y _) Z = ⊥-elim (x≢y refl)
uniq-∋ (S _ ∋x) (S _ ∋x) = uniq-∋ ∋x ∋x
-- A synthesized type is unique.
uniq-↑ : {Γ M A B} Γ M A Γ M B A B
uniq-↑ (⊢` ∋x) (⊢` ∋x) = uniq-∋ ∋x ∋x
uniq-↑ (⊢L · ⊢M) (⊢L · ⊢M) = rng≡ (uniq-↑ ⊢L ⊢L)
uniq-↑ (⊢↓ ⊢M) (⊢↓ ⊢M) = refl
-- Failed lookups still fail if a different binding is added.
ext∋ : {Γ B x y}
x y
¬ ∃[ A ]( Γ x A )
-----------------------------
¬ ∃[ A ]( Γ , y B x A )
ext∋ x≢y _ A , Z = x≢y refl
ext∋ _ ¬∃ A , S _ ⊢x = ¬∃ A , ⊢x
-- Decision procedure for lookup judgments.
lookup : (Γ : Context) (x : Id)
-----------------------
Dec (∃[ A ](Γ x A))
lookup x = no (λ ())
lookup (Γ , y B) x with x y
... | yes refl = yes B , Z
... | no x≢y with lookup Γ x
... | no ¬∃ = no (ext∋ x≢y ¬∃)
... | yes A , ⊢x = yes A , S x≢y ⊢x
-- Helpers for promoting a failure to type.
¬arg : {Γ A B L M}
Γ L A B
¬ Γ M A
-------------------------
¬ ∃[ B ](Γ L · M B)
¬arg ⊢L ¬⊢M B , ⊢L · ⊢M rewrite dom≡ (uniq-↑ ⊢L ⊢L) = ¬⊢M ⊢M
¬switch : {Γ M A B}
Γ M A
A B
---------------
¬ Γ (M ) B
¬switch ⊢M A≢B (⊢↑ ⊢M A≡B) rewrite uniq-↑ ⊢M ⊢M = A≢B A≡B
-- Mutually-recursive synthesize and inherit functions.
synthesize : (Γ : Context) (M : Term⁺)
-----------------------
Dec (∃[ A ](Γ M A))
inherit : (Γ : Context) (M : Term⁻) (A : Type)
---------------
Dec (Γ M A)
synthesize Γ (` x) with lookup Γ x
... | no ¬∃ = no (λ{ A , ⊢` ∋x ¬∃ A , ∋x })
... | yes A , ∋x = yes A , ⊢` ∋x
synthesize Γ (L · M) with synthesize Γ L
... | no ¬∃ = no (λ{ _ , ⊢L · _ ¬∃ _ , ⊢L })
... | yes ` , ⊢L = no (λ{ _ , ⊢L · _ ℕ≢⇒ (uniq-↑ ⊢L ⊢L) })
... | yes A B , ⊢L with inherit Γ M A
... | no ¬⊢M = no (¬arg ⊢L ¬⊢M)
... | yes ⊢M = yes B , ⊢L · ⊢M
synthesize Γ (M A) with inherit Γ M A
... | no ¬⊢M = no (λ{ _ , ⊢↓ ⊢M ¬⊢M ⊢M })
... | yes ⊢M = yes A , ⊢↓ ⊢M
inherit Γ (ƛ x N) ` = no (λ())
inherit Γ (ƛ x N) (A B) with inherit (Γ , x A) N B
... | no ¬⊢N = no (λ{ (⊢ƛ ⊢N) ¬⊢N ⊢N })
... | yes ⊢N = yes (⊢ƛ ⊢N)
inherit Γ `zero ` = yes ⊢zero
inherit Γ `zero (A B) = no (λ())
inherit Γ (`suc M) ` with inherit Γ M `
... | no ¬⊢M = no (λ{ (⊢suc ⊢M) ¬⊢M ⊢M })
... | yes ⊢M = yes (⊢suc ⊢M)
inherit Γ (`suc M) (A B) = no (λ())
inherit Γ (`case L [zero⇒ M |suc x N ]) A with synthesize Γ L
... | no ¬∃ = no (λ{ (⊢case ⊢L _ _) ¬∃ ` , ⊢L })
... | yes _ _ , ⊢L = no (λ{ (⊢case ⊢L _ _) ℕ≢⇒ (uniq-↑ ⊢L ⊢L) })
... | yes ` , ⊢L with inherit Γ M A
... | no ¬⊢M = no (λ{ (⊢case _ ⊢M _) ¬⊢M ⊢M })
... | yes ⊢M with inherit (Γ , x `) N A
... | no ¬⊢N = no (λ{ (⊢case _ _ ⊢N) ¬⊢N ⊢N })
... | yes ⊢N = yes (⊢case ⊢L ⊢M ⊢N)
inherit Γ (μ x N) A with inherit (Γ , x A) N A
... | no ¬⊢N = no (λ{ (⊢μ ⊢N) ¬⊢N ⊢N })
... | yes ⊢N = yes (⊢μ ⊢N)
inherit Γ (M ) B with synthesize Γ M
... | no ¬∃ = no (λ{ (⊢↑ ⊢M _) ¬∃ _ , ⊢M })
... | yes A , ⊢M with A ≟Tp B
... | no A≢B = no (¬switch ⊢M A≢B)
... | yes A≡B = yes (⊢↑ ⊢M A≡B)
-- Copied from Lambda.
_≠_ : (x y : Id) x y
x y with x y
... | no x≢y = x≢y
... | yes _ = ⊥-elim impossible
where postulate impossible :
-- Computed by evaluating 'synthesize ∅ 2+2' and editing.
⊢2+2 : 2+2 `
⊢2+2 =
(⊢↓
(⊢μ
(⊢ƛ
(⊢ƛ
(⊢case (⊢` (S (λ()) Z)) (⊢↑ (⊢` Z) refl)
(⊢suc
(⊢↑
(⊢`
(S (λ())
(S (λ())
(S (λ()) Z)))
· ⊢↑ (⊢` Z) refl
· ⊢↑ (⊢` (S (λ()) Z)) refl)
refl))))))
· ⊢suc (⊢suc ⊢zero)
· ⊢suc (⊢suc ⊢zero))
-- Check that synthesis is correct (more below).
_ : synthesize 2+2 yes ` , ⊢2+2
_ = refl
-- Example: 2+2 for Church numerals.
⊢2+2ᶜ : 2+2ᶜ `
⊢2+2ᶜ =
⊢↓
(⊢ƛ
(⊢ƛ
(⊢ƛ
(⊢ƛ
(⊢↑
(⊢`
(S (λ())
(S (λ())
(S (λ()) Z)))
· ⊢↑ (⊢` (S (λ()) Z)) refl
·
⊢↑
(⊢`
(S (λ())
(S (λ()) Z))
· ⊢↑ (⊢` (S (λ()) Z)) refl
· ⊢↑ (⊢` Z) refl)
refl)
refl)))))
·
⊢ƛ
(⊢ƛ
(⊢↑
(⊢` (S (λ()) Z) ·
⊢↑ (⊢` (S (λ()) Z) · ⊢↑ (⊢` Z) refl)
refl)
refl))
·
⊢ƛ
(⊢ƛ
(⊢↑
(⊢` (S (λ()) Z) ·
⊢↑ (⊢` (S (λ()) Z) · ⊢↑ (⊢` Z) refl)
refl)
refl))
· ⊢ƛ (⊢suc (⊢↑ (⊢` Z) refl))
· ⊢zero
_ : synthesize 2+2ᶜ yes ` , ⊢2+2ᶜ
_ = refl
-- Testing error cases.
_ : synthesize ((ƛ "x" ` "y" ) (` `)) no _
_ = refl
-- Bad argument type.
_ : synthesize (plus · sucᶜ) no _
_ = refl
-- Bad function types.
_ : synthesize (plus · sucᶜ · two) no _
_ = refl
_ : synthesize ((two `) · two) no _
_ = refl
_ : synthesize (twoᶜ `) no _
_ = refl
-- A natural can't have a function type.
_ : synthesize (`zero ` `) no _
_ = refl
_ : synthesize (two ` `) no _
_ = refl
-- Can't hide a bad type.
_ : synthesize (`suc twoᶜ `) no _
_ = refl
-- Can't case on a function type.
_ : synthesize
((`case (twoᶜ Ch) [zero⇒ `zero |suc "x" ` "x" ] `) ) no _
_ = refl
-- Can't hide a bad type inside case.
_ : synthesize
((`case (twoᶜ `) [zero⇒ `zero |suc "x" ` "x" ] `) ) no _
_ = refl
-- Mismatch of inherited and synthesized types.
_ : synthesize (((ƛ "x" ` "x" ) ` (` `))) no _
_ = refl
-- Erasure: Taking the evidence provided by synthesis on a decorated term
-- and producing the corresponding inherently-typed term.
-- Erasing a type.
∥_∥Tp : Type DB.Type
` ∥Tp = DB.`
A B ∥Tp = A ∥Tp DB.⇒ B ∥Tp
-- Erasing a context.
∥_∥Cx : Context DB.Context
∥Cx = DB.∅
Γ , x A ∥Cx = Γ ∥Cx DB., A ∥Tp
-- Erasing a lookup judgment.
∥_∥∋ : {Γ x A} Γ x A Γ ∥Cx DB.∋ A ∥Tp
Z ∥∋ = DB.Z
S x≢ ⊢x ∥∋ = DB.S ⊢x ∥∋
-- Mutually-recursive functions to erase typing judgments.
∥_∥⁺ : {Γ M A} Γ M A Γ ∥Cx DB.⊢ A ∥Tp
∥_∥⁻ : {Γ M A} Γ M A Γ ∥Cx DB.⊢ A ∥Tp
⊢` ⊢x ∥⁺ = DB.` ⊢x ∥∋
⊢L · ⊢M ∥⁺ = ⊢L ∥⁺ DB.· ⊢M ∥⁻
⊢↓ ⊢M ∥⁺ = ⊢M ∥⁻
⊢ƛ ⊢N ∥⁻ = DB.ƛ ⊢N ∥⁻
⊢zero ∥⁻ = DB.`zero
⊢suc ⊢M ∥⁻ = DB.`suc ⊢M ∥⁻
⊢case ⊢L ⊢M ⊢N ∥⁻ = DB.case ⊢L ∥⁺ ⊢M ∥⁻ ⊢N ∥⁻
⊢μ ⊢M ∥⁻ = DB.μ ⊢M ∥⁻
⊢↑ ⊢M refl ∥⁻ = ⊢M ∥⁺
-- Tests that erasure works.
_ : ⊢2+2 ∥⁺ DB.2+2
_ = refl
_ : ⊢2+2ᶜ ∥⁺ DB.2+2ᶜ
_ = refl
-- PLFA exercise: demonstrate that synthesis on your decorated multiplication
-- followed by erasure gives your inherently-typed multiplication.
-- PLFA exercise: extend the above to include products.
-- PLFA exercise (stretch): extend the above to include
-- the rest of the features added in More.
-- Additions by PR:
-- From Lambda, with type annotation added
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
-- Mutually-recursive decorators.
decorate⁻ : Term Term⁻
decorate⁺ : Term Term⁺
decorate⁻ (` x) = ` x
decorate⁻ (ƛ x M) = ƛ x decorate⁻ M
decorate⁻ (M · M₁) = (decorate⁺ M) · (decorate⁻ M₁)
decorate⁻ `zero = `zero
decorate⁻ (`suc M) = `suc (decorate⁻ M)
decorate⁻ `case M [zero⇒ M₁ |suc x M₂ ]
= `case (decorate⁺ M) [zero⇒ (decorate⁻ M₁) |suc x (decorate⁻ M₂) ]
decorate⁻ (μ x M) = μ x decorate⁻ M
decorate⁻ (M x) = decorate⁻ M
decorate⁺ (` x) = ` x
decorate⁺ (ƛ x M) = ⊥-elim impossible
where postulate impossible :
decorate⁺ (M · M₁) = (decorate⁺ M) · (decorate⁻ M₁)
decorate⁺ `zero = ⊥-elim impossible
where postulate impossible :
decorate⁺ (`suc M) = ⊥-elim impossible
where postulate impossible :
decorate⁺ `case M [zero⇒ M₁ |suc x M₂ ] = ⊥-elim impossible
where postulate impossible :
decorate⁺ (μ x M) = ⊥-elim impossible
where postulate impossible :
decorate⁺ (M x) = decorate⁻ M x
ltwo : Term
ltwo = `suc `suc `zero
lplus : Term
lplus = (μ "p" ƛ "m" ƛ "n"
`case ` "m"
[zero⇒ ` "n"
|suc "m" `suc (` "p" · ` "m" · ` "n") ])
(` ` `)
l2+2 : Term
l2+2 = lplus · ltwo · ltwo
ltwoᶜ : Term
ltwoᶜ = ƛ "s" ƛ "z" ` "s" · (` "s" · ` "z")
lplusᶜ : Term
lplusᶜ = (ƛ "m" ƛ "n" ƛ "s" ƛ "z"
` "m" · ` "s" · (` "n" · ` "s" · ` "z"))
(Ch Ch Ch)
lsucᶜ : Term
lsucᶜ = ƛ "x" `suc (` "x")
l2+2ᶜ : Term
l2+2ᶜ = lplusᶜ · ltwoᶜ · ltwoᶜ · lsucᶜ · `zero
_ : decorate⁻ ltwo two
_ = refl
_ : decorate⁺ lplus plus
_ = refl
_ : decorate⁺ l2+2 2+2
_ = refl
_ : decorate⁻ ltwoᶜ twoᶜ
_ = refl
_ : decorate⁺ lplusᶜ plusᶜ
_ = refl
_ : decorate⁻ lsucᶜ sucᶜ
_ = refl
_ : decorate⁺ l2+2ᶜ 2+2ᶜ
_ = refl
{-
Unicode used in this chapter:
↓ U+2193: DOWNWARDS ARROW (\d)
↑ U+2191: UPWARDS ARROW (\u)
∥ U+2225: PARALLEL TO (\||)
-}