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

module Generic.Semantics.TypeChecking where

open import Size
open import Function
open import Data.Unit using (; tt)
open import Data.Product
open import Data.List hiding ([_])
open import Data.Maybe using (Maybe; nothing; just)
import Data.Maybe.Categorical as MC

open import Data.Var hiding (_<$>_)
open import Data.Environment hiding (_<$>_ ; _>>_)
open import Generic.Syntax
open import Generic.Syntax.Bidirectional; open PATTERNS
open import Generic.Semantics

import Category.Monad as CM
import Level
module M = CM.RawMonad (MC.monad {Level.zero})
open M

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

infix 2 _=?_

_=?_ : (σ τ : Type)  Maybe 
α         =? α         = just tt
(σ `→ τ)  =? (φ `→ ψ)  = (σ =? φ) >> (τ =? ψ)
_         =? _         = nothing

isArrow : Type  Maybe (Type × Type)
isArrow (σ `→ τ)  = just (σ , τ)
isArrow _         = nothing


private
  variable
    i : Mode
    Γ : List Mode


Type- : Mode  Set
Type- Check  = Type   Maybe 
Type- Infer  =         Maybe Type

data Var- : Mode  Set where
  `var : Type  Var- Infer

app : Type- Infer  Type- Check  Type- Infer
app f t = do
  arr       f
  (σ , τ)   isArrow arr
  τ <$ t σ

cut : Type  Type- Check  Type- Infer
cut σ t = σ <$ t σ

emb : Type- Infer  Type- Check
emb t σ = do
  τ  t
  σ =? τ

lam : Kripke (const  Var-) (const  Type-) (Infer  []) Check Γ  Type- Check
lam b arr = do
  (σ , τ)  isArrow arr
  b (bind Infer) (ε  `var σ) τ

Typecheck : Semantics Bidi (const  Var-) (const  Type-)
Semantics.th^𝓥  Typecheck = th^const
Semantics.var   Typecheck = λ where (`var σ)  just σ
Semantics.alg   Typecheck = λ where
  (`app' f t)   app f t
  (`cut' σ t)   cut σ t
  (`emb' t)     emb t
  (`lam' b)     lam b

type- :  p  TM Bidi p  Type- p
type- p = Semantics.closed Typecheck

module _ where

  private β = α `→ α


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