{-# OPTIONS --allow-unsolved-meta #-}


{-
  SIMPLY-TYPED LAMBDA CALCULUS :-)

  examples for terms in STLC:
  I = λx. x       (in Agda notation: λ x → x, in blackboard: x ↦ x)
  K = λx. λy. x   (in Agda notation: λ x → λ y → x)
  0 = λs. λz. z
  1 = λs. λz. s z
  2 = λs. λz. s (s z)
  3 = λs. λz. s (s (s z))
      λ.  λ.  1 (1 (1 0))   "de Bruijn indices"

  ingredients for terms in STLC:
  - variables
  - application
  - lambda abstraction
  - primitives for zero and successor
-}

data  : Set where
  zero : 
  succ :   

-- "Ty" will be the Agda type of all the types available to STLC
data Ty : Set where
  *    : Ty             -- denoting the type of natural numbers
  _⇒_ : Ty  Ty  Ty   -- for function types A ⇒ B

⟦_⟧ : Ty  Set   -- \[[...\]]
 *        = 
 τ  τ'  =  τ    τ' 

-- "Term" will be the Agda type of all terms in STLC
{- This is more a type of "raw terms":
data Term : Set where
  var : String → Term         -- beware of nonsensical terms: "foo" (can be made
                              -- meaningful by: "λfoo. foo")
  app : Term → Term → Term    -- beware of type errors
  abs : String → Term → Term
-}

-- "Cxt" will be the Agda datatype of possible STLC contexts
data Cxt : Set where
  ε   : Cxt
  _,_ : Cxt  Ty  Cxt

-- "τ ∈ Γ" is the Agda datatype of witnesses that the context Γ
-- somewhere contains a variable of type τ
data _∈_ : Ty  Cxt  Set where
  here  : {Γ : Cxt} {τ : Ty}  τ  (Γ , τ)  -- the de Bruijn index 0
  there : {Γ : Cxt} {τ τ' : Ty}  τ  Γ  τ  (Γ , τ')

-- "Term Γ τ" will be the Agda datatype of STLC terms of type τ in context Γ
data Term : Cxt  Ty  Set where
  Z   : {Γ : Cxt}  Term Γ *
  S   : {Γ : Cxt}  Term Γ (*  *)
  var : {Γ : Cxt} {τ : Ty}  τ  Γ  Term Γ τ
  app : {Γ : Cxt} {τ τ' : Ty}  Term Γ (τ  τ')  Term Γ τ  Term Γ τ'
  abs : {Γ : Cxt} {τ τ' : Ty}  Term (Γ , τ) τ'  Term Γ (τ  τ')

-- "Env Γ" will be the Agda datatype of "environments of shape Γ";
-- these map each variable declaration in Γ to some value
data Env : Cxt  Set where
     : Env ε
  _∷ʳ_ : {Γ : Cxt} {τ : Ty}  Env Γ   τ   Env (Γ , τ)

lookup : {Γ : Cxt} {τ : Ty}  Env Γ  τ  Γ   τ 
lookup (Γ ∷ʳ x) here      = x
lookup (Γ ∷ʳ x) (there p) = lookup Γ p

eval : {Γ : Cxt} {τ : Ty}  Env Γ  Term Γ τ   τ 
eval env Z         = zero
eval env S         = succ
eval env (var v)   = lookup env v
eval env (app f x) = (eval env f) (eval env x)
eval env (abs t)   = λ x  eval (env ∷ʳ x) t

I : Term ε (*  *)
I = abs (var here)    -- λx. x

open import Padova2024.EquationalReasoning

_ : eval  I   x  x)
_ = refl

K : Term ε (*  (*  *))
K = abs (abs (var (there here)))   -- λx. λy. x

_ : eval  (app S (app S (app S Z)))  succ (succ (succ zero))
_ = refl