{-# OPTIONS --safe --sized-types #-}
module Generic.Semantics.Elaboration.Typed where

import Level
open import Size
open import Function
import Category.Monad as CM
open import Data.Bool
open import Data.Product as Prod
open import Data.List hiding ([_] ; lookup)
open import Data.List.Relation.Unary.All as All hiding (lookup)
open import Data.Maybe as Maybe using (Maybe; nothing; just)
open import Category.Monad
import Data.Maybe.Categorical as MC
open RawMonad (MC.monad {Level.zero})

open import Generic.Syntax.Bidirectional
open import Generic.Syntax.STLC as S

open import Relation.Unary hiding (_∈_)
open import Data.Var hiding (_<$>_)
open import Data.Environment hiding (_<$>_)
open import Generic.Syntax
open import Generic.Semantics

open import Relation.Binary.PropositionalEquality hiding ([_])


Typing : List Mode  Set
Typing = All (const Type)


private
  variable
    σ : Type
    m : Mode
    ms ns : List Mode

⌞_⌟ : Typing ms  List Type
 []      = []
 σ  Γ   = σ   Γ 

Elab : Type ─Scoped  Type  (ms : List Mode)  Typing ms  Set
Elab T σ _ Γ = T σ  Γ 

Elab- : Mode ─Scoped
Elab- Check  ms =  Γ  (σ : Type)  Maybe (Elab (Tm STLC ) σ ms Γ)
Elab- Infer  ms =  Γ  Maybe (Σ[ σ  Type ] Elab (Tm STLC ) σ ms Γ)

data Var- : Mode ─Scoped where
  `var : (infer :  Γ  Σ[ σ  Type ] Elab Var σ ms Γ)  Var- Infer ms

open import Data.List.Relation.Unary.Any hiding (lookup)
open import Data.List.Membership.Propositional

toVar : m  ms  Var m ms
toVar (here refl) = z
toVar (there v) = s (toVar v)

fromVar : Var m ms  m  ms
fromVar z = here refl
fromVar (s v) = there (fromVar v)

coth^Typing : Typing ns  Thinning ms ns  Typing ms
coth^Typing Δ ρ = All.tabulate  x∈Γ  All.lookup Δ (fromVar (lookup ρ (toVar x∈Γ))))

lookup-fromVar :  Δ (v : Var m ms)  Var (All.lookup Δ (fromVar v))  Δ 
lookup-fromVar (_  _) z     = z
lookup-fromVar (_  _) (s v) = s (lookup-fromVar _ v)

erase^coth :  ms Δ (ρ : Thinning ms ns) 
             Var σ  coth^Typing Δ ρ   Var σ  Δ 
erase^coth []       Δ ρ ()
erase^coth (m  ms) Δ ρ z     = lookup-fromVar Δ (lookup ρ z)
erase^coth (m  ms) Δ ρ (s v) = erase^coth ms Δ (select weaken ρ) v

th^Var- : Thinnable (Var- m)
th^Var- (`var infer) ρ = `var λ Δ 
  let (σ , v) = infer (coth^Typing Δ ρ) in
  σ , erase^coth _ Δ ρ v

open Semantics

_=?_ : (σ τ : Type)  Maybe (σ  τ)
α         =? α         = just refl
(σ `→ τ)  =? (φ `→ ψ)  = do
  refl  σ =? φ
  refl  τ =? ψ
  return refl
_ =? _ = nothing

data Arrow : Type  Set where
  _`→_ :  σ τ  Arrow (σ `→ τ)

isArrow :  σ  Maybe (Arrow σ)
isArrow (σ `→ τ)  = just (σ `→ τ)
isArrow _         = nothing

app : ∀[ Elab- Infer  Elab- Check  Elab- Infer ]
app f t Γ = do
  (arr , F)   f Γ
  (σ `→ τ)    isArrow arr
  T           t Γ σ
  return (τ , `app F T)

var₀ : Var- Infer (Infer  ms)
var₀ = `var λ where (σ  _)  (σ , z)

lam : ∀[ Kripke Var- Elab- (Infer  []) Check  Elab- Check ]
lam b Γ arr = do
  (σ `→ τ)   isArrow arr
  B          b (bind Infer) (ε  var₀) (σ  Γ) τ
  return (`lam B)

emb : ∀[ Elab- Infer  Elab- Check ]
emb t Γ σ = do
  (τ , T)   t Γ
  refl      σ =? τ
  return T

cut : Type  ∀[ Elab- Check  Elab- Infer ]
cut σ t Γ = (σ ,_) <$> t Γ σ

Elaborate : Semantics Bidi Var- Elab-
Elaborate .th^𝓥  = th^Var-
Elaborate .var   = λ where (`var infer) Γ  just (map₂ `var (infer Γ))
Elaborate .alg   = λ where
  (`app' f t)   app f t
  (`lam' b)     lam b
  (`emb' t)     emb t
  (`cut' σ t)   cut σ t

    where open PATTERNS

Type- : Mode  Set
Type- Check  =  σ  Maybe (TM STLC σ)
Type- Infer  = Maybe ( λ σ  TM STLC σ)

type- :  p  TM Bidi p  Type- p
type- Check  t = closed Elaborate t []
type- Infer  t = closed Elaborate t []

module B = PATTERNS

module _ where

  private
    β : Type
    β = α `→ α

  _ :  type- Infer  ( B.`app (B.`cut (β `→ β)  id^B)  id^B)
      just (β      , S.`app                   id^S   id^S)
  _ = refl