-- Syntax: Types, terms and contexts.
module Syntax where

open import Library

infixr 6 _⇒_
infixr 4 _,_

-- Types and contexts.

data Ty : Set where
  ★   : Ty
  _⇒_ : (a b : Ty) → Ty

data Cxt : Set where
  ε   : Cxt
  _,_ : (Γ : Cxt) (a : Ty) → Cxt

-- Variables and terms.

data Var : (Γ : Cxt) (a : Ty) → Set where
  zero : ∀ {Γ a}                 → Var (Γ , a) a
  suc  : ∀ {Γ a b} (x : Var Γ a) → Var (Γ , b) a

data Tm (Γ : Cxt) : (a : Ty) → Set where
  var : ∀ {a}   (x : Var Γ a)                   → Tm Γ a
  abs : ∀ {a b} (t : Tm (Γ , a) b)              → Tm Γ (a ⇒ b)
  app : ∀ {a b} (t : Tm Γ (a ⇒ b)) (u : Tm Γ a) → Tm Γ b

-- Generalized neutral terms.

data GNe (Arg : Cxt → Ty → Set) (Γ : Cxt) : Ty → Set where
  var : ∀{a}    (x : Var Γ a)                         → GNe Arg Γ a
  app : ∀{a b}  (n : GNe Arg Γ (a ⇒ b)) (o : Arg Γ a) → GNe Arg Γ b

-- βη-normal forms.

mutual

  Ne = GNe Nf

  data Nf (Γ : Cxt) : Ty → Set where
    abs : ∀{a b}  (o : Nf (Γ , a) b)  → Nf Γ (a ⇒ b)
    ne  :         (n : Ne Γ ★)        → Nf Γ ★

mutual
  embNe : ∀{Γ a} → Ne Γ a → Tm Γ a
  embNe (var x) = var x
  embNe (app t u) = app (embNe t) (embNf u)

  embNf : ∀{Γ a} → Nf Γ a → Tm Γ a
  embNf (ne t) = embNe t
  embNf (abs t) = abs (embNf t)

-- Values and environments.

mutual
  data Env (i : Size) (Δ : Cxt) : (Γ : Cxt) → Set where
    ε   : Env i Δ ε
    _,_ : ∀ {Γ a} (ρ : Env i Δ Γ) (v : Val i Δ a) → Env i Δ (Γ , a)

  NeVal = λ i → GNe (Val i)

  data Val (i : Size) (Δ : Cxt) : (a : Ty) → Set where
    ne    : ∀{a}      (n : NeVal i Δ a)                   → Val i Δ a
    lam   : ∀{Γ a b}  (t : Tm (Γ , a) b) (ρ : Env i Δ Γ)  → Val i Δ (a ⇒ b)
    later : ∀{a}      (v∞ : ∞Val i Δ a)                   → Val i Δ a

  record ∞Val (i : Size) (Δ : Cxt) (a : Ty) : Set where
    coinductive
    constructor ∞val
    field
      force : {j : Size< i} → Val j Δ a

open ∞Val public

  -- Note: this is not the same thing as Delay i (Val i Δ a)
  -- because now the sizes are not uniform, but the size is
  -- the sum on the longest path

  -- ALT:
  -- data Delay (i : Size) (A : Size → Set) : Set where
  --   now : A i → Delay i A
  --   ...
  -- but we would need to tell Agda that A is antitone
  -- otherwise Delay i A is not antitone in i

-- strong bisimilarity for values, neutral values and environments

mutual
  Val∋_≈⟨_⟩≈_   = λ {Δ}{a} a? i b? → Val∋_≈_ {i}{Δ}{a} a? b?
  NeVal∋_≈⟨_⟩≈_ = λ {Δ}{a} a? i b? → NeVal∋_≈_ {i}{Δ}{a} a? b?
  Env∋_≈⟨_⟩≈_   = λ {Δ}{Γ} a? i b? → Env∋_≈_ {i}{Δ}{Γ} a? b?

  data NeVal∋_≈_ {i}{Δ} : {a : Ty}(a? b? : NeVal ∞ Δ a) → Set where
    ≈var : ∀{a}{x : Var Δ a}                      → NeVal∋ var x ≈ var x
    ≈app : ∀{a b}{n n' : NeVal ∞ Δ (a ⇒ b)}       → NeVal∋ n ≈⟨ i ⟩≈ n' →
           {v v' : Val ∞ Δ a} → Val∋ v ≈⟨ i ⟩≈ v' → NeVal∋ app n v ≈ app n' v'

  data Env∋_≈_ {i}{Δ} : ∀{Γ} → Env ∞ Δ Γ → Env ∞ Δ Γ → Set where
    ≈ε   : Env∋ ε ≈ ε
    _≈,_ : ∀{Γ a}{ρ ρ' : Env ∞ Δ Γ} → Env∋ ρ ≈⟨ i ⟩≈ ρ' →
           {v v' : Val ∞ Δ a} → Val∋ v ≈⟨ i ⟩≈ v' → Env∋ (ρ , v) ≈ (ρ' , v')

  data Val∋_≈_ {i}{Δ} : {a : Ty}(a? b? : Val ∞ Δ a) → Set where
    ≈lam   : ∀{Γ a b}{t : Tm (Γ , a) b}{ρ ρ' : Env ∞ Δ Γ} → Env∋ ρ ≈⟨ i ⟩≈ ρ' →
             Val∋ lam t ρ ≈ lam t ρ'
    ≈ne    : ∀{a}{n n' : NeVal ∞ Δ a} → NeVal∋ n ≈⟨ i ⟩≈ n' → Val∋ ne n ≈ ne n'
    ≈later : ∀ {a}{a∞ b∞ : ∞Val ∞ Δ a}(eq : ∞Val∋ a∞ ≈⟨ i ⟩≈ b∞) →
             Val∋ later a∞ ≈ later b∞

  record ∞Val∋_≈⟨_⟩≈_ {Δ a} (a∞ : ∞Val ∞ Δ a) i (b∞ : ∞Val ∞ Δ a) : Set where
    coinductive
    field
      ≈force : {j : Size< i} → Val∋ force a∞ ≈⟨ j ⟩≈ force b∞

  ∞Val∋_≈_ = λ {i}{Δ}{a} a? b? → ∞Val∋_≈⟨_⟩≈_ {Δ}{a} a? i b?

open ∞Val∋_≈⟨_⟩≈_ public

mutual
  ≈reflVal : ∀{i}{Δ}{a}(v : Val ∞ Δ a) → Val∋ v ≈⟨ i ⟩≈ v
  ≈reflVal {i} (ne n) = ≈ne (≈reflNeVal {i = i} n)
  ≈reflVal (lam t ρ)  = ≈lam (≈reflEnv ρ)
  ≈reflVal (later v∞) = ≈later (∞≈reflVal v∞)

  ∞≈reflVal : ∀{i}{Δ}{a}(v : ∞Val ∞ Δ a) → ∞Val∋ v ≈⟨ i ⟩≈ v
  ≈force (∞≈reflVal v) = ≈reflVal (force v)

  ≈reflNeVal : ∀{i}{Δ}{a}(v : NeVal ∞ Δ a) → NeVal∋ v ≈⟨ i ⟩≈ v
  ≈reflNeVal (var x) = ≈var
  ≈reflNeVal (app v o) = ≈app (≈reflNeVal v) (≈reflVal o)

  ≈reflEnv : ∀{i}{Δ}{Γ}(e : Env ∞ Δ Γ) → Env∋ e ≈⟨ i ⟩≈ e
  ≈reflEnv ε = ≈ε
  ≈reflEnv (e , v) = ≈reflEnv e ≈, ≈reflVal v

mutual
  ≈symVal : ∀{i}{Δ}{a}{v v' : Val ∞ Δ a} → Val∋ v ≈⟨ i ⟩≈ v' →
            Val∋ v' ≈⟨ i ⟩≈ v
  ≈symVal (≈lam p) = ≈lam (≈symEnv p )
  ≈symVal (≈ne p)  = ≈ne (≈symNeVal p)
  ≈symVal (≈later p) = ≈later (∞≈symVal p)

  ∞≈symVal : ∀{i}{Δ}{a}{v v' : ∞Val ∞ Δ a} → ∞Val∋ v ≈⟨ i ⟩≈ v' →
             ∞Val∋ v' ≈⟨ i ⟩≈ v
  ≈force (∞≈symVal p) = ≈symVal (≈force p)

  ≈symNeVal : ∀{i}{Δ}{a}{v v' : NeVal ∞ Δ a} →
              NeVal∋ v ≈⟨ i ⟩≈ v' → NeVal∋ v' ≈⟨ i ⟩≈ v
  ≈symNeVal ≈var       = ≈var
  ≈symNeVal (≈app p q) = ≈app (≈symNeVal p) (≈symVal q)

  ≈symEnv : ∀{i}{Δ}{Γ}{e e' : Env ∞ Δ Γ} →
             Env∋ e ≈⟨ i ⟩≈ e' → Env∋ e' ≈⟨ i ⟩≈ e
  ≈symEnv ≈ε       = ≈ε
  ≈symEnv (p ≈, q) = ≈symEnv p ≈, ≈symVal q

mutual
  ≈transVal : ∀{i}{Δ}{a}{v v' v'' : Val ∞ Δ a} → Val∋ v ≈⟨ i ⟩≈ v' →
            Val∋ v' ≈⟨ i ⟩≈ v'' → Val∋ v ≈⟨ i ⟩≈ v''
  ≈transVal (≈lam p)   (≈lam p')   = ≈lam (≈transEnv p p')
  ≈transVal (≈ne p)    (≈ne p')    = ≈ne (≈transNeVal p p')
  ≈transVal (≈later p) (≈later p') = ≈later (∞≈transVal p p')

  ∞≈transVal : ∀{i}{Δ}{a}{v v' v'' : ∞Val ∞ Δ a} → ∞Val∋ v ≈⟨ i ⟩≈ v' →
              ∞Val∋ v' ≈⟨ i ⟩≈ v'' → ∞Val∋ v ≈⟨ i ⟩≈ v''
  ≈force (∞≈transVal p q) = ≈transVal (≈force p) (≈force q)

  ≈transNeVal : ∀{i}{Δ}{a}{v v' v'' : NeVal ∞ Δ a} →
                NeVal∋ v ≈⟨ i ⟩≈ v' → NeVal∋ v' ≈⟨ i ⟩≈ v'' →
                NeVal∋ v ≈⟨ i ⟩≈ v''
  ≈transNeVal ≈var       ≈var        = ≈var
  ≈transNeVal (≈app p q) (≈app p' q') =
    ≈app (≈transNeVal p p' ) (≈transVal q q')

  ≈transEnv : ∀{i}{Δ}{a}{v v' v'' : Env ∞ Δ a} → Env∋ v ≈⟨ i ⟩≈ v' →
    Env∋ v' ≈⟨ i ⟩≈ v'' → Env∋ v ≈⟨ i ⟩≈ v''
  ≈transEnv ≈ε       ≈ε         = ≈ε
  ≈transEnv (p ≈, q) (p' ≈, q') = (≈transEnv p p') ≈, ≈transVal q q'

≈Valsetoid : (i : Size)(Δ : Cxt)(a : Ty) → Setoid lzero lzero
≈Valsetoid i Δ a = record
  { Carrier       = Val ∞ Δ a
  ; _≈_           = Val∋_≈_ {i}
  ; isEquivalence = record
    { refl  = ≈reflVal _
    ; sym   = ≈symVal
    ; trans = ≈transVal
    }
  }

module ≈Val-Reasoning {i : Size}{Δ : Cxt}{a : Ty} where
  open SetoidReasoning (≈Valsetoid i Δ a) public