module Talk where
open import Data.Nat hiding (_<_)
data Ty : Set where
  nat : Ty
  _⇒_ : Ty → Ty → Ty
data Con : Set where
  ε   : Con
  _<_ : Con → Ty → Con
data Var : Con → Ty → Set where
  zero : ∀{Γ σ} → Var (Γ < σ) σ
  suc  : ∀{Γ σ τ} → Var Γ σ → Var (Γ < τ) σ
data Tm : Con → Ty → Set where
  var : ∀{Γ σ} → Var Γ σ → Tm Γ σ
  lam : ∀{Γ σ τ} → Tm (Γ < σ) τ → Tm Γ (σ ⇒ τ)
  app : ∀{Γ σ τ} → Tm Γ (σ ⇒ τ) → Tm Γ σ → Tm Γ τ
  zero : ∀{Γ} → Tm Γ nat
  suc : ∀{Γ} → Tm Γ nat → Tm Γ nat
  prim : ∀{Γ σ} → Tm Γ nat → Tm Γ σ → Tm Γ (σ ⇒ σ) → Tm Γ σ
Val : Ty → Set
Val nat      = ℕ
Val (σ ⇒ σ₁) = Val σ → Val σ₁
Env : Con → Set
Env Γ = {σ : _} → Var Γ σ → Val σ
_<'_ : ∀{Γ σ} → Env Γ → Val σ → Env (Γ < σ)
(γ <' v) zero = v
(γ <' v) (suc x) = γ x
vprim : {X : Set} → ℕ → X → (X → X) → X
vprim zero z f = z
vprim (suc n) z f = f (vprim n z f)
⟦_⟧ : ∀{Γ σ} → Tm Γ σ → (Env Γ → Val σ)
⟦ var x      ⟧ γ = γ x
⟦ lam t      ⟧ γ = λ v → ⟦ t ⟧ (γ <' v)
⟦ app t u    ⟧ γ = ⟦ t ⟧ γ (⟦ u ⟧ γ)
⟦ zero       ⟧ γ = 0
⟦ suc t      ⟧ γ = 1 + (⟦ t ⟧ γ)
⟦ prim t z f ⟧ γ = vprim (⟦ t ⟧ γ) (⟦ z ⟧ γ) (⟦ f ⟧ γ)
two : ∀{Γ} → Tm Γ nat
two = suc (suc zero)
plus : ∀{Γ} → Tm Γ (nat ⇒ (nat ⇒ nat))
plus = lam (lam (prim (var (suc zero)) (var zero) (lam (suc (var zero)))))
example : ∀{Γ} → Tm Γ nat
example = app (app plus two) two
empty : Env ε
empty ()
test : ℕ
test = ⟦ example ⟧ empty