{-# OPTIONS --safe --sized-types #-}

module Motivation.Problem.Naive where

open import Relation.Unary
open import Data.Var hiding (_<$>_)
open import Data.Environment
open import Data.Relation

open import Function
open import Relation.Binary.PropositionalEquality hiding ([_])
open ≡-Reasoning
open import Data.List hiding ([_] ; lookup)

open import StateOfTheArt.ACMM using (Type; α; _`→_) public

private
  variable
    σ τ : Type
    Γ Δ : List Type


data S : Type ─Scoped where
  `var  : ∀[ Var σ ⇒ S σ ]
  `lam  : ∀[ (σ ∷_) ⊢ S τ ⇒ S (σ `→ τ) ]
  `app  : ∀[ S (σ `→ τ) ⇒ S σ ⇒ S τ ]
  `let  : ∀[ S σ ⇒ (σ ∷_) ⊢ S τ  ⇒ S τ ]

data T : Type ─Scoped where
  `var  : ∀[ Var σ ⇒ T σ ]
  `lam  : ∀[ (σ ∷_) ⊢ T τ ⇒ T (σ `→ τ) ]
  `app  : ∀[ T (σ `→ τ) ⇒ T σ ⇒ T τ ]

th^T : Thinnable (T σ)
th^T (`var v)    ρ = `var (lookup ρ v)
th^T (`lam b)    ρ = `lam (th^T b (th^Env th^Var ρ weaken ∙ z))
th^T (`app f t)  ρ = `app (th^T f ρ) (th^T t ρ)

unlet : (Γ ─Env) T Δ → S σ Γ → T σ Δ
unlet ρ (`var v)    = lookup ρ v
unlet ρ (`lam b)    = `lam (unlet (th^Env th^T ρ weaken ∙ `var z) b)
unlet ρ (`app f t)  = `app (unlet ρ f) (unlet ρ t)
unlet ρ (`let e t)  = unlet (ρ ∙ unlet ρ e) t

th^S : Thinnable (S σ)
th^S (`var v)    ρ = `var (lookup ρ v)
th^S (`lam b)    ρ = `lam (th^S b (th^Env th^Var ρ weaken ∙ z))
th^S (`app f t)  ρ = `app (th^S f ρ) (th^S t ρ)
th^S (`let e t)  ρ = `let (th^S e ρ) (th^S t (th^Env th^Var ρ weaken ∙ z))

sub^S : (Γ ─Env) S Δ → S σ Γ → S σ Δ
sub^S ρ (`var v)    = lookup ρ v
sub^S ρ (`lam b)    = `lam (sub^S (th^Env th^S ρ weaken ∙ `var z) b)
sub^S ρ (`app f t)  = `app (sub^S ρ f) (sub^S ρ t)
sub^S ρ (`let e t)  = `let (sub^S ρ e) (sub^S (th^Env th^S ρ weaken ∙ `var z) t)

sub^T : (Γ ─Env) T Δ → T σ Γ → T σ Δ
sub^T ρ (`var v)    = lookup ρ v
sub^T ρ (`lam b)    = `lam (sub^T (th^Env th^T ρ weaken ∙ `var z) b)
sub^T ρ (`app f t)  = `app (sub^T ρ f) (sub^T ρ t)

_⟨_/0⟩^S : ∀[ (σ ∷_) ⊢ S τ ⇒ S σ ⇒ S τ ]
b ⟨ t /0⟩^S = sub^S (`var <$> identity ∙ t) b

_⟨_/0⟩^T : ∀[ (σ ∷_) ⊢ T τ ⇒ T σ ⇒ T τ ]
b ⟨ t /0⟩^T = sub^T (`var <$> identity ∙ t) b


module _ where
 infix 1 _⊢_∋_↝S_

 private
  variable
    b c : S τ (σ ∷ Γ)
    f g : S (σ `→ τ) Γ
    d e t u : S σ Γ

 data _⊢_∋_↝S_ : ∀ Γ σ → S σ Γ → S σ Γ → Set where
 -- computation
   β      : ∀ (b : S τ (σ ∷ Γ)) u → Γ ⊢ τ ∋ `app (`lam b) u ↝S b ⟨ u /0⟩^S
   ζ      : ∀ e (t : S τ (σ ∷ Γ)) → Γ ⊢ τ ∋ `let e t ↝S t ⟨ e /0⟩^S
 -- structural
   `lam   : (σ ∷ Γ) ⊢ τ ∋ b ↝S c → Γ ⊢ σ `→ τ ∋ `lam b ↝S `lam c
   `appl  : Γ ⊢ σ `→ τ ∋ f ↝S g → ∀ t → Γ ⊢ τ ∋ `app f t ↝S `app g t
   `appr  : ∀ f → Γ ⊢ σ ∋ t ↝S u → Γ ⊢ τ ∋ `app f t ↝S `app f u
   `letl  : Γ ⊢ σ ∋ d ↝S e → ∀ t → Γ ⊢ τ ∋ `let d t ↝S `let e t
   `letr  : ∀ e → (σ ∷ Γ) ⊢ τ ∋ t ↝S u → Γ ⊢ τ ∋ `let e t ↝S `let e u

module _ where
 infix 1 _⊢_∋_↝T_

 private
  variable
    b c : T τ (σ ∷ Γ)
    f g : T (σ `→ τ) Γ
    d e t u : T σ Γ

 data _⊢_∋_↝T_ : ∀ Γ σ → T σ Γ → T σ Γ → Set where
 -- computation
   β      : ∀ {Γ σ τ} (b : T τ (σ ∷ Γ)) u → Γ ⊢ τ ∋ `app (`lam b) u ↝T b ⟨ u /0⟩^T
 -- structural
   `lam   : (σ ∷ Γ) ⊢ τ ∋ b ↝T c → Γ ⊢ σ `→ τ ∋ `lam b ↝T `lam c
   `appl  : Γ ⊢ σ `→ τ ∋ f ↝T g → ∀ t → Γ ⊢ τ ∋ `app f t ↝T `app g t
   `appr  : ∀ f → Γ ⊢ σ ∋ t ↝T u → Γ ⊢ τ ∋ `app f t ↝T `app f u