{-# OPTIONS --rewriting #-}

module A201802.WIP.LR1a where

open import A201801.Prelude
open import A201801.Category
open import A201801.Fin
open import A201801.FinLemmas
open import A201801.Vec
open import A201801.VecLemmas
open import A201801.AllVec


--------------------------------------------------------------------------------


infixr 8 _⊃_
data Type : Set
  where
    bool : Type
    _⊃_  : Type → Type → Type


Types : Nat → Set
Types g = Vec Type g


--------------------------------------------------------------------------------


data Exp (g : Nat) : Set
  where
    var   : Fin g → Exp g
    lam   : Exp (suc g) → Exp g
    app   : Exp g → Exp g → Exp g
    true  : Exp g
    false : Exp g
    if    : Exp g → Exp g → Exp g → Exp g


Exps : Nat → Nat → Set
Exps g n = Vec (Exp g) n


ren : ∀ {g g′} → g′ ≥ g → Exp g
               → Exp g′
ren r (var i)       = var (REN∋ r i)
ren r (lam e)       = lam (ren (keep r) e)
ren r (app e₁ e₂)   = app (ren r e₁) (ren r e₂)
ren r true          = true
ren r false         = false
ren r (if e₁ e₂ e₃) = if (ren r e₁) (ren r e₂) (ren r e₃)


rens : ∀ {g g′ n} → g′ ≥ g → Exps g n
                  → Exps g′ n
rens r s = MAPS (ren r) s


wk : ∀ {g} → Exp g
           → Exp (suc g)
wk e = ren (drop id≥) e


wks : ∀ {g n} → Exps g n
              → Exps (suc g) n
wks s = rens (drop id≥) s


vz : ∀ {g} → Exp (suc g)
vz = var zero


lifts : ∀ {g n} → Exps g n
                → Exps (suc g) (suc n)
lifts s = wks s , vz


vars : ∀ {g g′} → g′ ≥ g
                → Exps g′ g
vars done     = ∙
vars (drop r) = wks (vars r)
vars (keep r) = lifts (vars r)


ids : ∀ {g} → Exps g g
ids = vars id≥


sub : ∀ {g n} → Exps g n → Exp n
              → Exp g
sub s (var i)       = GET s i
sub s (lam e)       = lam (sub (lifts s) e)
sub s (app e₁ e₂)   = app (sub s e₁) (sub s e₂)
sub s true          = true
sub s false         = false
sub s (if e₁ e₂ e₃) = if (sub s e₁) (sub s e₂) (sub s e₃)


subs : ∀ {g n m} → Exps g n → Exps n m
                 → Exps g m
subs s₁ s₂ = MAPS (sub s₁) s₂


cut : ∀ {g} → Exp g → Exp (suc g)
            → Exp g
cut e₁ e₂ = sub (ids , e₁) e₂


--------------------------------------------------------------------------------


infix 3 _⊢_⦂_
data _⊢_⦂_ {g} (Γ : Types g) : Exp g → Type → Set
  where
    VAR : ∀ {τ i} → Γ ∋⟨ i ⟩ τ
                  → Γ ⊢ var i ⦂ τ

    LAM : ∀ {τ₁ τ₂ e} → Γ , τ₁ ⊢ e ⦂ τ₂
                      → Γ ⊢ lam e ⦂ τ₁ ⊃ τ₂

    APP : ∀ {τ₁ τ₂ e₁ e₂} → Γ ⊢ e₁ ⦂ τ₁ ⊃ τ₂ → Γ ⊢ e₂ ⦂ τ₁
                          → Γ ⊢ app e₁ e₂ ⦂ τ₂

    TRUE : Γ ⊢ true ⦂ bool

    FALSE : Γ ⊢ false ⦂ bool

    IF : ∀ {τ e₁ e₂ e₃} → Γ ⊢ e₁ ⦂ bool → Γ ⊢ e₂ ⦂ τ → Γ ⊢ e₃ ⦂ τ
                        → Γ ⊢ if e₁ e₂ e₃ ⦂ τ


infix 3 _⊢_⦂_all
_⊢_⦂_all : ∀ {g n} → Types g → Exps g n → Types n → Set
Γ ⊢ s ⦂ Ξ all = All (\ { (e , τ) → Γ ⊢ e ⦂ τ }) (zip s Ξ)


REN : ∀ {g g′ r e τ} → {Γ : Types g} {Γ′ : Types g′}
                     → Γ′ ⊇⟨ r ⟩ Γ → Γ ⊢ e ⦂ τ
                     → Γ′ ⊢ ren r e ⦂ τ
REN ρ (VAR I)       = VAR (ren∋ ρ I)
REN ρ (LAM D)       = LAM (REN (keep ρ) D)
REN ρ (APP D₁ D₂)   = APP (REN ρ D₁) (REN ρ D₂)
REN ρ TRUE          = TRUE
REN ρ FALSE         = FALSE
REN ρ (IF D₁ D₂ D₃) = IF (REN ρ D₁) (REN ρ D₂) (REN ρ D₃)


RENS : ∀ {g g′ r n} → {Γ : Types g} {Γ′ : Types g′}
                       {s : Exps g n} {Ξ : Types n}
                    → Γ′ ⊇⟨ r ⟩ Γ → Γ ⊢ s ⦂ Ξ all
                    → Γ′ ⊢ rens r s ⦂ Ξ all
RENS {s = ∙}     {∙}     ρ ∙       = ∙
RENS {s = s , e} {Ξ , τ} ρ (σ , D) = RENS ρ σ , REN ρ D


WK : ∀ {g e τ₁ τ₂} → {Γ : Types g}
                   → Γ ⊢ e ⦂ τ₂
                   → Γ , τ₁ ⊢ wk e ⦂ τ₂
WK D = REN (drop id⊇) D


WKS : ∀ {g n τ} → {Γ : Types g} {s : Exps g n} {Ξ : Types n}
                → Γ ⊢ s ⦂ Ξ all
                → Γ , τ ⊢ wks s ⦂ Ξ all
WKS σ = RENS (drop id⊇) σ


VZ : ∀ {g τ} → {Γ : Types g}
             → Γ , τ ⊢ vz ⦂ τ
VZ = VAR zero


LIFTS : ∀ {g n τ} → {Γ : Types g} {s : Exps g n} {Ξ : Types n}
                  → Γ ⊢ s ⦂ Ξ all
                  → Γ , τ ⊢ lifts s ⦂ Ξ , τ all
LIFTS σ = WKS σ , VZ


VARS : ∀ {g g′ r} → {Γ : Types g} {Γ′ : Types g′}
                  → Γ′ ⊇⟨ r ⟩ Γ
                  → Γ′ ⊢ vars r ⦂ Γ all
VARS done     = ∙
VARS (drop ρ) = WKS (VARS ρ)
VARS (keep ρ) = LIFTS (VARS ρ)


IDS : ∀ {g} → {Γ : Types g}
            → Γ ⊢ ids ⦂ Γ all
IDS = VARS id⊇


SUB : ∀ {g n e τ} → {Γ : Types g} {s : Exps g n} {Ξ : Types n}
                  → Γ ⊢ s ⦂ Ξ all → Ξ ⊢ e ⦂ τ
                  → Γ ⊢ sub s e ⦂ τ
SUB σ (VAR I)       = get σ (zip∋₂ I)
SUB σ (LAM D)       = LAM (SUB (LIFTS σ) D)
SUB σ (APP D₁ D₂)   = APP (SUB σ D₁) (SUB σ D₂)
SUB σ TRUE          = TRUE
SUB σ FALSE         = FALSE
SUB σ (IF D₁ D₂ D₃) = IF (SUB σ D₁) (SUB σ D₂) (SUB σ D₃)


SUBS : ∀ {g n m} → {Γ : Types g} {s₁ : Exps g n} {Ξ₁ : Types n}
                    {s₂ : Exps n m} {Ξ₂ : Types m}
                 → Γ ⊢ s₁ ⦂ Ξ₁ all → Ξ₁ ⊢ s₂ ⦂ Ξ₂ all
                 → Γ ⊢ subs s₁ s₂ ⦂ Ξ₂ all
SUBS {s₂ = ∙}      {∙}      σ₁ ∙        = ∙
SUBS {s₂ = s₂ , e} {Ξ₂ , τ} σ₁ (σ₂ , D) = SUBS σ₁ σ₂ , SUB σ₁ D


CUT : ∀ {g e₁ e₂ τ₁ τ₂} → {Γ : Types g}
                        → Γ ⊢ e₁ ⦂ τ₁ → Γ , τ₁ ⊢ e₂ ⦂ τ₂
                        → Γ ⊢ cut e₁ e₂ ⦂ τ₂
CUT D₁ D₂ = SUB (IDS , D₁) D₂


--------------------------------------------------------------------------------