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