Algorithmic.Soundness

module Algorithmic.Soundness where

open import Function using (_∘_)
open import Data.Empty using ()
open import Data.Vec using (Vec;[];_∷_)
open import Data.Product using (_×_) renaming (_,_ to _,,_)
open import Data.Unit using (;tt)
open import Relation.Binary.PropositionalEquality
              using (_≡_;refl;sym;trans;cong;cong₂)
              renaming (subst to substEq)
open Relation.Binary.PropositionalEquality.≡-Reasoning

open import Utils using (Kind;*;;_⇒_)
open import Utils.List using (List;[];_∷_)
open import Type using (Ctx⋆;;_,⋆_;_⊢⋆_;_∋⋆_;S;Z)
open _⊢⋆_

open import Type.RenamingSubstitution using (_[_];sub-cons;sub-cong;weaken;sub;sub∅)
open import Type.Equality using (_≡β_;≡2β)
open _≡β_

import Declarative as Dec
import Algorithmic as Alg
import Algorithmic.Signature as Alg
open import Type.BetaNormal using (_⊢Nf⋆_;_⊢Ne⋆_;embNf;embNe;ren-embNf;weakenNf;embNf-VecList;embNf-List;lookup-embNf-VecList)
open _⊢Nf⋆_
open _⊢Ne⋆_

open import Type.BetaNBE using (nf;eval;idEnv)
open import Type.BetaNBE.Completeness using (sub-eval;idCR;idext;reflectCR;fund)
open import Type.BetaNBE.Soundness using (soundness)
open import Type.BetaNBE.RenamingSubstitution using (_[_]Nf;subNf;subNf-cons;subNf∅;subNf∅≡subNf)
open import Builtin using (Builtin)
open import Type.BetaNBE.Stability
open import Algorithmic.Completeness using (btype-lem)
embCtx : ∀{Φ}  Alg.Ctx Φ  Dec.Ctx Φ
embCtx Alg.∅       = Dec.∅
embCtx (Γ Alg.,⋆ K) = embCtx Γ Dec.,⋆ K
embCtx (Γ Alg., A)  = embCtx Γ Dec., embNf A
embVar : ∀{Φ Γ}{A : Φ ⊢Nf⋆ *}
   Γ Alg.∋ A
   embCtx Γ Dec.∋ embNf A
embVar Alg.Z     = Dec.Z
embVar (Alg.S α) = Dec.S (embVar α)
embVar (Alg.T {A = A} α) =
  Dec.conv∋ refl (sym (ren-embNf S A)) (Dec.T (embVar α))
emb[] : ∀{Γ K}(A : Γ ⊢Nf⋆ K)(B : Γ ,⋆ K ⊢Nf⋆ *) 
  (embNf B [ embNf A ]) ≡β embNf (B [ A ]Nf)
emb[] A B = trans≡β
  (soundness (embNf B [ embNf A ]))
  (≡2β (cong embNf
    (trans
      (trans
        (sub-eval (embNf B) idCR (sub-cons ` (embNf A)))
        (idext  { Z  idext idCR (embNf A)
                  ; (S α)  reflectCR (refl {x = ` α})}) (embNf B)))
      (sym (sub-eval (embNf B) idCR (embNf  subNf-cons (ne  `) A))))))
soundness-μ : ∀{Φ Φ' K}(p : Φ  Φ')(A : Φ ⊢Nf⋆ (K  *)  K  *)(B : Φ ⊢Nf⋆ K) 
  embNf A · ƛ (μ (weaken (embNf A)) (` Z)) · embNf B ≡β
  embNf
    (nf (embNf A · ƛ (μ (embNf (weakenNf A)) (` Z)) · embNf B))
soundness-μ p A B = trans≡β
  (soundness (embNf A · ƛ (μ (weaken (embNf A)) (` Z)) · embNf B))
  (≡2β (cong  X  embNf (nf (embNf A · ƛ (μ X (` Z)) · embNf B)))
             (sym (ren-embNf S A))))
lemσ' : ∀{Γ Γ' Δ Δ'}(bn : Builtin)(p : Γ  Γ')
   (C : Δ ⊢⋆ *)(C' : Δ' ⊢Nf⋆ *)  (q : Δ  Δ')
   (σ : {J : Kind}  Δ' ∋⋆ J  Γ ⊢Nf⋆ J)
   nf C  substEq (_⊢Nf⋆ *) (sym q) C' 
  sub
   {J} α 
     substEq (_⊢⋆ J) p
     (embNf (σ (substEq (_∋⋆ J) q α))))
  C
  ≡β
  substEq (_⊢⋆ *) p
  (embNf
   (eval
    (sub  {J₁} x  embNf (σ x))
     (embNf C'))
    (idEnv Γ)))
lemσ' bn refl C C' refl σ p =  trans≡β
  (soundness (sub (embNf  σ) C))
  (trans≡β
    (≡2β (cong embNf (sub-eval C idCR (embNf  σ))))
    (trans≡β
      (≡2β (cong embNf (fund  α  idext  idCR (embNf (σ α))) (soundness C))))
      (trans≡β (≡2β (sym (cong embNf (sub-eval (embNf (nf C)) idCR (embNf  σ))))) (≡2β (cong embNf (cong nf (cong (sub (embNf  σ)) (cong embNf p))))))))

_≡βL_ : ∀{Δ}  (As As' : List (Δ ⊢⋆ *))  Set
[]       ≡βL []         = 
[]       ≡βL (A'  As') = 
(A  As) ≡βL []         = 
(A  As) ≡βL (A'  As') = (A ≡β A') × (As ≡βL As')

refl≡βL : ∀{Δ}  (As : List (Δ ⊢⋆ *))  As ≡βL As
refl≡βL [] = tt
refl≡βL (x  As) = (refl≡β x) ,, (refl≡βL As)

embList : ∀{Δ}  List (Δ ⊢Nf⋆ *)  List (Δ ⊢⋆ *)
embList []       = []
embList (A  As) = embNf A  embList As

lemsub : ∀{Γ Δ}(A : Δ ⊢Nf⋆ )(A' : Δ ⊢⋆ )
   (σ : {J : Kind}  Δ ∋⋆ J  Γ ⊢Nf⋆ J)
   embNf A ≡β A' 
  (embNf (subNf σ A)) ≡β
  sub  {J} α  embNf (σ α)) A'
lemsub A A' σ p = trans≡β
  (trans≡β
    (≡2β (cong embNf (sub-eval (embNf A) idCR (embNf  σ))))
    (trans≡β
      (≡2β (cong embNf (fund  α  idext  idCR (embNf (σ α))) p)))
      ((≡2β (sym (cong embNf (sub-eval A' idCR (embNf  σ))))))))
  (sym≡β (soundness (sub (embNf  σ) A')))

subNf-sub∅-lem :  Φ (A :  ⊢Nf⋆ )  embNf {Φ} (subNf (λ()) A) ≡β sub∅ (embNf A)
subNf-sub∅-lem Φ A = trans≡β (lemsub A (embNf A)  {J}  λ()) (refl≡β (embNf A)))
                             (≡2β (sub-cong  {()}) (embNf A)))

subNf∅-sub∅-lem :  Φ  (A :  ⊢Nf⋆ )   embNf {Φ} (subNf∅ A) ≡β sub∅ (embNf A)
subNf∅-sub∅-lem Φ A rewrite subNf∅≡subNf {Φ} {A = A} = subNf-sub∅-lem Φ A

btype-lem≡β : ∀{Φ} b  Dec.btype {Φ} b ≡β embNf (Alg.btype b)
btype-lem≡β {Φ} b rewrite btype-lem {Φ} b = soundness (Dec.btype {Φ} b)

emb : ∀{Φ Γ}{A : Φ ⊢Nf⋆ *}  Γ Alg.⊢ A  embCtx Γ Dec.⊢ embNf A

emb-ConstrArgs :  {Φ} {Γ : Alg.Ctx Φ}
                   {Ts : List (Φ ⊢Nf⋆ *)}
                   (cs : Alg.ConstrArgs Γ Ts) 
                 Dec.ConstrArgs (embCtx Γ) (embNf-List Ts)
emb-ConstrArgs [] = []
emb-ConstrArgs (x  cs) = (emb x)  (emb-ConstrArgs cs)

lema-mkCaseType : ∀{Φ}{A : Φ ⊢Nf⋆ *} As 
     embNf (Alg.mkCaseType A As)  Dec.mkCaseType (embNf A) (embNf-List As)
lema-mkCaseType [] = refl
lema-mkCaseType (A  As) = cong (embNf A ⇒_) (lema-mkCaseType As)

emb-Cases :  {Φ} {Γ : Alg.Ctx Φ} {A : Φ ⊢Nf⋆ *} {n}
         {Tss : Vec (List (Φ ⊢Nf⋆ *)) n}
         (cases : Alg.Cases Γ A Tss)
         Dec.Cases (embCtx Γ) (embNf A) (embNf-VecList Tss)
emb-Cases Alg.[] = Dec.[]
emb-Cases (Alg._∷_ {Ts = Ts} c cases) = substEq (embCtx _ Dec.⊢_) (lema-mkCaseType Ts) (emb c)
                            Dec.∷ (emb-Cases cases)

emb (Alg.` α) = Dec.` (embVar α)
emb (Alg.ƛ {A = A}{B} t) = Dec.ƛ (emb t)
emb (Alg._·_ {A = A}{B} t u) = emb t Dec.· emb u
emb (Alg.Λ {B = B} t) = Dec.Λ (emb t)
emb (Alg._·⋆_/_ {B = B} t A refl) =
    Dec.conv (emb[] A B) (emb t Dec.·⋆ embNf A)
emb (Alg.wrap A B t) = Dec.wrap
  (embNf A)
  (embNf B)
  (Dec.conv (sym≡β (soundness-μ refl A B)) (emb t))
emb (Alg.unwrap {A = A}{B} t refl) =
  Dec.conv (soundness-μ refl A B) (Dec.unwrap (emb t))
emb (Alg.con {A = A} t refl ) = Dec.con {A = embNf A} (substEq Alg.⟦_⟧ (sym (stability A)) t) (subNf∅-sub∅-lem _ A)
emb (Alg.builtin b / refl) = Dec.conv (btype-lem≡β b) (Dec.builtin b)
emb (Alg.error A) = Dec.error (embNf A)
emb (Alg.constr e Tss refl cs) = Dec.constr e (embNf-VecList Tss) (sym (lookup-embNf-VecList e Tss)) (emb-ConstrArgs cs)
emb (Alg.case x cases) = Dec.case (emb x) (emb-Cases cases)

soundnessT : ∀{Φ Γ}{A : Φ ⊢Nf⋆ *}  Γ Alg.⊢ A  embCtx Γ Dec.⊢ embNf A
soundnessT = emb