module A201602.STLCVarSupply where module Stream where open import Data.Nat using (ℕ; zero; suc) open import Data.Product using (_,_; _×_) open import Data.Vec using (Vec; []; _∷_) record Stream (X : Set) : Set where coinductive field head : X tail : Stream X open Stream public take+ : {X : Set} → Stream X → X × Stream X take+ ∞ = head ∞ , tail ∞ takeN+ : {X : Set} → (n : ℕ) → Stream X → Vec X n × Stream X takeN+ zero ∞ = [] , ∞ takeN+ (suc n) ∞ = let (x , ∞′) = take+ ∞ (xs , ∞″) = takeN+ n ∞′ in x ∷ xs , ∞″ module Var where open import Data.Nat using (ℕ) open import Data.Product using (_,_; proj₁; _×_) open import Data.String using (String) open import Data.Vec using (Vec; []; _∷_; zipWith) open Stream using (Stream) infixr 4 _,_ VarSupply : Set VarSupply = Stream ℕ next : VarSupply → VarSupply next = Stream.tail record Var : Set where constructor _,_ field name : String serial : ℕ open Var public make+ : String → VarSupply → Var × VarSupply make+ n ∞ = let s , ∞′ = Stream.take+ ∞ in (n , s) , ∞′ make2+ : String → String → VarSupply → (Var × Var) × VarSupply make2+ n₁ n₂ ∞ = let v₁ , ∞′ = make+ n₁ ∞ v₂ , ∞″ = make+ n₂ ∞′ in (v₁ , v₂) , ∞″ make3+ : String → String → String → VarSupply → (Var × Var × Var) × VarSupply make3+ n₁ n₂ n₃ ∞ = let (v₁ , v₂) , ∞′ = make2+ n₁ n₂ ∞ v₃ , ∞″ = make+ n₃ ∞′ in (v₁ , v₂ , v₃) , ∞″ make4+ : String → String → String → String → VarSupply → (Var × Var × Var × Var) × VarSupply make4+ n₁ n₂ n₃ n₄ ∞ = let (v₁ , v₂) , ∞′ = make2+ n₁ n₂ ∞ (v₃ , v₄) , ∞″ = make2+ n₃ n₄ ∞′ in (v₁ , v₂ , v₃ , v₄) , ∞″ makeN+ : ∀{n} → Vec String n → VarSupply → Vec Var n × VarSupply makeN+ {n} ns ∞ = let ss , ∞′ = Stream.takeN+ n ∞ in zipWith _,_ ns ss , ∞′ make : String → VarSupply → Var make n ∞ = proj₁ (make+ n ∞) make2 : String → String → VarSupply → Var × Var make2 n₁ n₂ ∞ = proj₁ (make2+ n₁ n₂ ∞) make3 : String → String → String → VarSupply → Var × Var × Var make3 n₁ n₂ n₃ ∞ = proj₁ (make3+ n₁ n₂ n₃ ∞) make4 : String → String → String → String → VarSupply → Var × Var × Var × Var make4 n₁ n₂ n₃ n₄ ∞ = proj₁ (make4+ n₁ n₂ n₃ n₄ ∞) makeN : ∀{n} → Vec String n → VarSupply → Vec Var n makeN ns ∞ = proj₁ (makeN+ ns ∞) check : Var → VarSupply → Var check x ∞ = make (name x) ∞ module STLC where open Var using (Var; VarSupply; check; next) infixr 4 _,_ infixl 3 _$_ infixr 2 𝜆_∙_ infixr 1 _⊃_ infixr 0 _∣_⊢_∷_ infixr 0 _⊩_∷_ data Ty : Set where ⊥ : Ty _⊃_ : Ty → Ty → Ty data Tm : Set where 𝑣_ : Var → Tm 𝜆_∙_ : Var → Tm → Tm _$_ : Tm → Tm → Tm record Hyp : Set where constructor _,_ field term : Tm type : Ty open Hyp public data Cx : Set where ∅ : Cx _,_ : Cx → Hyp → Cx data _∈_ : Hyp → Cx → Set where Z : ∀{Γ h} → h ∈ (Γ , h) S_ : ∀{Γ h h′} → h ∈ Γ → h ∈ (Γ , h′) data _∣_⊢_∷_ (∞ : VarSupply) (Γ : Cx) : Tm → Ty → Set where M𝑣_ : ∀{A t} → (t , A) ∈ Γ → ∞ ∣ Γ ⊢ t ∷ A M𝜆 : ∀{A B x t} → next ∞ ∣ Γ , (𝑣 (check x ∞) , A) ⊢ t ∷ B → ∞ ∣ Γ ⊢ 𝜆 x ∙ t ∷ A ⊃ B M∘ : ∀{A B t s} → ∞ ∣ Γ ⊢ t ∷ A ⊃ B → ∞ ∣ Γ ⊢ s ∷ A → ∞ ∣ Γ ⊢ t $ s ∷ B _⊩_∷_ : VarSupply → Tm → Ty → Set ∞ ⊩ t ∷ A = ∀{Γ} → ∞ ∣ Γ ⊢ t ∷ A open import Data.Product using (_,_) open Var using (make; make2; make3) open STLC eI : ∀{A ∞} → let x = make "x" ∞ in ∞ ⊩ 𝜆 x ∙ 𝑣 x ∷ A ⊃ A eI = M𝜆 (M𝑣 Z) eK : ∀{A B ∞} → let x , y = make2 "x" "y" ∞ in ∞ ⊩ 𝜆 x ∙ 𝜆 y ∙ 𝑣 x ∷ A ⊃ B ⊃ A eK = M𝜆 (M𝜆 (M𝑣 S Z)) eS : ∀{A B C ∞} → let f , g , x = make3 "f" "g" "x" ∞ in ∞ ⊩ 𝜆 f ∙ 𝜆 g ∙ 𝜆 x ∙ (𝑣 f $ 𝑣 x) $ (𝑣 g $ 𝑣 x) ∷ (A ⊃ B ⊃ C) ⊃ (A ⊃ B) ⊃ A ⊃ C eS = M𝜆 (M𝜆 (M𝜆 (M∘ (M∘ (M𝑣 S S Z) (M𝑣 Z)) (M∘ (M𝑣 S Z) (M𝑣 Z)))))