{-# OPTIONS --rewriting #-}

module Reflect4Direct where

import DS
import CPS
open import CPS-DS

open import Data.Unit
open import Data.Empty
open import Data.Product
open import Function
open import Relation.Binary.PropositionalEquality

-- postulate
postulate
  lemma-Var-subst : {var : CPS.Ty  Set} {τ₁ τ₂ : CPS.Ty}
                    {Δ : CPS.Delta} {σ : CPS.Mc}
                    {e : var τ₁  CPS.term[ var , Δ , σ ]⇒ τ₂} 
                    {x : var τ₁} 
                    CPS.Subst e (CPS.Var x) (e x)

-- substitution lemma
mutual
  -- v₁[x:=v] = v₂
  lemma-SubstV : {var : DS.Ty  Set}  {τ₁ τ₂ : CPS.Ty} 
                 {v₁ : (var  dsT) τ₁  CPS.value[ var  dsT ] τ₂} 
                 {v  : CPS.value[ var  dsT ] τ₁} 
                 {v₂ : CPS.value[ var  dsT ] τ₂} 
                 CPS.SubstV v₁ v v₂ 
                 DS.SubstV {var}  x  dsV (v₁ x)) (dsV v) (dsV v₂)
  lemma-SubstV CPS.sVar= = DS.sVar=
  lemma-SubstV CPS.sVar≠ = DS.sVar≠
  lemma-SubstV CPS.sNum = DS.sNum
  lemma-SubstV CPS.sBol = DS.sBol
  lemma-SubstV (CPS.sFun sub) =
    DS.sFun  x  lemma-Subst (sub x))
  lemma-SubstV (CPS.sShift id) = DS.sShift (ds-id-cont-type id)
  lemma-SubstV CPS.sShift0 = DS.sShift0

  -- e₁[x:=v] = e₂
  lemma-Subst : {var : DS.Ty  Set} {Δ : CPS.Delta} 
                {τ β : CPS.Ty} {σβ : CPS.Mc} 
                {e₁ : (var  dsT) τ  CPS.term[ var  dsT , Δ , σβ ]⇒ β} 
                {v  : CPS.value[ var  dsT ] τ} 
                {e₂ : CPS.term[ var  dsT , Δ , σβ ]⇒ β} 
                CPS.Subst e₁ v e₂ 
                DS.Subst {var}  x  dsE (e₁ x)) (dsV v) (dsE e₂)
  lemma-Subst (CPS.sVal ΔΘ sub-c sub-v sub-m) =
    DS.substPlugM (lemma-SubstM ΔΘ sub-m)
      (DS.substPlug (lemma-SubstC sub-c) (DS.sVal (lemma-SubstV sub-v)))
  lemma-Subst (CPS.sApp ΔΘ sub-v₁ sub-v₂ sub-c sub-m) =
    DS.substPlugM (lemma-SubstM ΔΘ sub-m)
      (DS.substPlug (lemma-SubstC sub-c)
                    (DS.sNonVal (DS.sApp (DS.sVal (lemma-SubstV sub-v₁))
                                         (DS.sVal (lemma-SubstV sub-v₂)))))

  -- c₁[x:=v] = c₂
  lemma-SubstC : {var : DS.Ty  Set} {Δ : CPS.Delta} 
                 {τ α τ₁ : CPS.Ty} {σα : CPS.Mc} 
                 {c₁ : (var  dsT) τ₁ 
                            CPS.cont[ var  dsT , Δ ] (τ CPS.⇒ σα  α)} 
                 {v  : CPS.value[ var  dsT ] τ₁} 
                 {c₂ : CPS.cont[ var  dsT , Δ ] (τ CPS.⇒ σα  α)} 
                 CPS.SubstC c₁ v c₂ 
                 DS.SubstC {var}  x  dsC (c₁ x)) (dsV v) (dsC c₂)
  lemma-SubstC CPS.sKVar≠ = DS.sHole
  lemma-SubstC (CPS.sKId id) = DS.sHole
  lemma-SubstC {Δ = CPS.K (τ CPS.⇒ σα  α)} (CPS.sKLet sub) =
    DS.sLet DS.sHole  x  lemma-Subst (sub x))
  lemma-SubstC {Δ = CPS.• (γ CPS.⇒ σid  γ') id} (CPS.sKLet sub) =
    DS.sLet DS.sHole  x  lemma-Subst (sub x))

  -- m₁[x:=v] = m₂
  lemma-SubstM : {var : DS.Ty  Set} {Δ : CPS.Delta} {Θ : CPS.Theta} 
                 {τ : CPS.Ty} {σ σβ : CPS.Mc} 
                 (ΔΘ : CPS.Delta-Theta Δ Θ) 
                 {m₁ : (var  dsT) τ 
                            CPS.mcont[ var  dsT , Θ , σβ ] σ } 
                 {v  : CPS.value[ var  dsT ] τ} 
                 {m₂ : CPS.mcont[ var  dsT , Θ , σβ ] σ} 
                 CPS.SubstM m₁ v m₂ 
                 DS.SubstM {var}
                            x  dsM ΔΘ (m₁ x)) (dsV v) (dsM ΔΘ m₂)
  lemma-SubstM tt CPS.sGVar≠ = DS.sGHole
  lemma-SubstM {Δ = CPS.• (γ CPS.⇒ σid  γ') id}
               tt (CPS.sGCons {Δ' = τ CPS.⇒ σα  α} ΔΘ sub-c sub-m) =
    DS.sGReset (ds-id-cont-type id)
               (lemma-SubstC sub-c) (lemma-SubstM ΔΘ sub-m)

mutual
  -- e₁[k:=c] = e₂ => c[e₁] → e₂
  lemma-CSubst : {var : DS.Ty  Set} {Δ : CPS.Delta}
                 {τ α β : CPS.Ty} {σ σα : CPS.Mc} 
                 {e₁ : CPS.term[ var  dsT , CPS.K (τ CPS.⇒ σα  α) , σ ]⇒ β} 
                 {c  : CPS.cont[ var  dsT , Δ ] (τ CPS.⇒ σα  α)} 
                 {e₂ : CPS.term[ var  dsT , Δ , σ ]⇒ β} 
                 CPS.CSubst e₁ c e₂ 
                 DS.Reduce {var} (DS.plug (dsC c) (dsE e₁)) (dsE e₂)
  lemma-CSubst (CPS.sVal₁ {m = CPS.GVar} csub-c) = lemma-CSubstC csub-c
  lemma-CSubst (CPS.sVal₂ csub-m) = lemma-CSubstM csub-m
  lemma-CSubst (CPS.sApp₁ {m = CPS.GVar} csub-c) = lemma-CSubstC csub-c
  lemma-CSubst (CPS.sApp₂ csub-m) = lemma-CSubstM csub-m

  -- c₁[k:=c] = c₂ => c[c₁[e]] → c₂[e]
  lemma-CSubstC : {var : DS.Ty  Set} {Δ : CPS.Delta}
                  {τ α β τ₁ τ₂ : CPS.Ty} {σ σα σβ : CPS.Mc} 
                  {c₁ : CPS.cont[ var  dsT , CPS.K (τ₁ CPS.⇒ σ  τ₂)
                                                      ] (τ CPS.⇒ σα  α)} 
                  {c  : CPS.cont[ var  dsT , Δ ] (τ₁ CPS.⇒ σ  τ₂ )} 
                  {c₂ : CPS.cont[ var  dsT , Δ ] (τ CPS.⇒ σα  α)} 
                  {e  : DS.term[ var , dsT τ DS.▷⟨ dsMc σα  dsT α
                                                      ]⟨ dsMc σβ  dsT β} 
                  CPS.CSubstC c₁ c c₂ 
                  DS.Reduce {var}
                            (DS.plug (dsC c) (DS.plug (dsC c₁) e))
                            (DS.plug (dsC c₂) e)
  lemma-CSubstC {c = CPS.KVar} CPS.sKVar= = DS.RId
  lemma-CSubstC {c = CPS.KId id} CPS.sKVar= = DS.RId
  lemma-CSubstC {Δ = CPS.K (τ₁ CPS.⇒ σ  τ₂)}
                {c = CPS.KLet e} CPS.sKVar= = DS.RId
  lemma-CSubstC {Δ = CPS.• (γ CPS.⇒ σid  γ') id}
                {c = CPS.KLet e} CPS.sKVar= = DS.RId
  lemma-CSubstC {c = CPS.KVar} (CPS.sKLet₂ csub) =
    DS.RLet₂  x  lemma-CSubst (csub x))
  lemma-CSubstC {c = CPS.KId id₁} (CPS.sKLet₂ csub) =
    DS.RLet₂  x  lemma-CSubst (csub x))
  lemma-CSubstC {Δ = CPS.K (τ₁ CPS.⇒ σ  τ₂)} {c = CPS.KLet e} {e = e'}
                (CPS.sKLet₂ {e₁ = e₁} {e₂ = e₂} csub) = begin
    DS.NonVal
      (DS.Let
        (DS.NonVal (DS.Let e'  x  dsE (e₁ x))))
         x  dsE (e x)))
    ⟶⟨ DS.RAssoc e'  x  dsE (e₁ x))  x  dsE (e x)) 
    DS.NonVal
       (DS.Let e'
         x  DS.NonVal (DS.Let (dsE (e₁ x))  x  dsE (e x)))))
    ⟶⟨ DS.RLet₂  x  lemma-CSubst (csub x)) 
    DS.NonVal (DS.Let e'  x  dsE (e₂ x)))
    
    where open DS.Reasoning
  lemma-CSubstC {Δ = CPS.• (γ CPS.⇒ σid  γ') id} {c = CPS.KLet e} {e = e'}
                (CPS.sKLet₂ {e₁ = e₁} {e₂ = e₂} csub) = begin
    DS.NonVal
      (DS.Let
        (DS.NonVal (DS.Let e'  x  dsE (e₁ x))))
         x  dsE (e x)))
    ⟶⟨ DS.RAssoc e'  x  dsE (e₁ x))  x  dsE (e x)) 
    DS.NonVal
       (DS.Let e'
         x  DS.NonVal (DS.Let (dsE (e₁ x))  x  dsE (e x)))))
    ⟶⟨ DS.RLet₂  x  lemma-CSubst (csub x)) 
    DS.NonVal (DS.Let e'  x  dsE (e₂ x)))
    
    where open DS.Reasoning

  -- m₁[k:=c] = m₂
  lemma-CSubstM : {var : DS.Ty  Set} {Δ : CPS.Delta}
                  {τ α β : CPS.Ty} {κ : CPS.CTy} {σ σα σβ : CPS.Mc} 
                  {id : CPS.id-cont-type κ} 
                  {m₁ : CPS.mcont[ var  dsT ,
                                    CPS.D (CPS.K (τ CPS.⇒ σα  α)) , σ ] σβ} 
                  {c  : CPS.cont[ var  dsT , Δ ] (τ CPS.⇒ σα  α)} 
                  {m₂ : CPS.mcont[ var  dsT , CPS.D Δ , σ ] σβ} 
                  {e : DS.term[ var , dsΔ (CPS.• κ id) ]⟨ dsMc σβ  dsT β} 
                  CPS.CSubstM m₁ c m₂ 
                  DS.Reduce {var}
                    (DS.plug (dsC c) (DS.plugM (dsM {Δ = CPS.• κ id} tt m₁) e))
                    (DS.plugM (dsM {Δ = CPS.• κ id} tt m₂) e)
  lemma-CSubstM {κ = γ CPS.⇒ σid  γ'} 
                (CPS.sGCons₁ {κ' = τ₁ CPS.⇒ σ₁  τ₂} {m = CPS.GVar} csub-c) = 
    lemma-CSubstC csub-c
  lemma-CSubstM {κ = γ CPS.⇒ σid  γ'}
                (CPS.sGCons₂ {κ'' = τ₁ CPS.⇒ σ₁  τ₂} csub-m) =
    lemma-CSubstM csub-m

--mutual
  -- e₁[g:=m] = e₂ => m[e₁] = e₂
  lemma-MSubst : {var : DS.Ty  Set} {Δ Δ' : CPS.Delta} {Θ : CPS.Theta} 
                 {β : CPS.Ty} {σ σβ : CPS.Mc} 
                 (ΔΘ : CPS.Delta-Theta Δ Θ) 
                 {e₁ : CPS.term[ var  dsT , Δ , σβ ]⇒ β} 
                 {m  : CPS.mcont[ var  dsT , Θ , σ ] σβ} 
                 {e₂ : CPS.term[ var  dsT , Δ' , σ ]⇒ β} 
                 (eq : Δ'  Δ CPS.++ Θ) 
                 CPS.MSubst e₁ m eq e₂ 
                 DS.plugM (dsM ΔΘ m) (dsE e₁)
                  subst  Δ  DS.term[ var , Δ ]⟨ dsMc σ  dsT β)
                         (cong dsΔ eq)
                         (dsE e₂)
  lemma-MSubst ΔΘ eq (CPS.sVal _ _ msub-m) = lemma-MSubstM ΔΘ msub-m
  lemma-MSubst ΔΘ eq (CPS.sApp _ _ _ _ _ _ msub-m) =
    lemma-MSubstM ΔΘ msub-m
  
  -- m₁[g:=m] = m₂ => m[m₁[e]] = m₂[e]
  lemma-MSubstM : {var : DS.Ty  Set} {Δ : CPS.Delta} {Θ Θ' : CPS.Theta} 
                  {β : CPS.Ty} {σ σβ σ' : CPS.Mc} 
                  (ΔΘ : CPS.Delta-Theta (Δ CPS.++ Θ') Θ) 
                  {ΔΘ' : CPS.Delta-Theta Δ (Θ' CPS.+++ Θ)} 
                  {ΔΘ'' : CPS.Delta-Theta Δ Θ'} 
                  {m₁ : CPS.mcont[ var  dsT , Θ' , σ' ] σβ} 
                  {m  : CPS.mcont[ var  dsT , Θ , σ ] σ'} 
                  {m₂ : CPS.mcont[ var  dsT , Θ' CPS.+++ Θ , σ ] σβ} 
                  {e  : DS.term[ var , dsΔ Δ ]⟨ dsMc σβ  dsT β} 
                  CPS.MSubstM m₁ m refl m₂ 
                  DS.plugM (dsM ΔΘ m) (DS.plugM (dsM ΔΘ'' m₁) e)
                   (DS.plugM (dsM ΔΘ' m₂) e)
  lemma-MSubstM ΔΘ {ΔΘ'} CPS.mGVar= rewrite CPS.ΔΘ≡ ΔΘ' ΔΘ = refl
  lemma-MSubstM {Δ = CPS.• (γ CPS.⇒ σid  γ') id}
                ΔΘ (CPS.mGCons {κ = τ CPS.⇒ σα  α} _ _ msub-m) =
    lemma-MSubstM ΔΘ msub-m 
  
-- RBetaLet
redBetaLet : {var : DS.Ty  Set} {Δ : CPS.Delta} {Θ : CPS.Theta} 
             {τ β : CPS.Ty} {σ σβ : CPS.Mc} 
             (ΔΘ : CPS.Delta-Theta Δ Θ) 
             {e₁  : (var  dsT) τ  CPS.term[ var  dsT , Δ , σ ]⇒ β} 
             {v   : CPS.value[ var  dsT ] τ} 
             {e₁' : CPS.term[ var  dsT , Δ , σ ]⇒ β} 
             {m   : CPS.mcont[ var  dsT , Θ , σβ ] σ} 
             {e₂  : CPS.term[ var  dsT , Δ CPS.++ Θ , σβ ]⇒ β} 
             CPS.Subst e₁ v e₁' 
             CPS.MSubst e₁' m refl e₂ 
             DS.Reduce {var}
               (DS.plugM (dsM ΔΘ m) 
                  (DS.plug (dsC (CPS.KLet e₁)) (DS.Val (dsV v))))
               (dsE e₂)
redBetaLet {Δ = CPS.K (τ CPS.⇒ σα  α)}
           ΔΘ {e₁} {v} {e₁'} {m} {e₂} sub msub = begin
  DS.plugM (dsM ΔΘ m) (DS.plug (dsC (CPS.KLet e₁)) (DS.Val _))
  ⟶⟨ DS.reducePlugM (dsM ΔΘ m) (DS.RBetaLet _ _ _ (lemma-Subst sub)) 
  DS.plugM (dsM ΔΘ m) (dsE e₁')
  ≡⟨ lemma-MSubst ΔΘ refl msub 
  dsE e₂
  
  where open DS.Reasoning
redBetaLet {Δ = CPS.• (γ CPS.⇒ σid  γ') id}
           ΔΘ {e₁} {v} {e₁'} {m} {e₂} sub msub = begin
  DS.plugM (dsM ΔΘ m) (DS.plug (dsC (CPS.KLet e₁)) (DS.Val _))
  ⟶⟨ DS.reducePlugM (dsM ΔΘ m) (DS.RBetaLet _ _ _ (lemma-Subst sub)) 
  DS.plugM (dsM ΔΘ m) (dsE e₁')
  ≡⟨ lemma-MSubst ΔΘ refl msub 
  dsE e₂
  
  where open DS.Reasoning

-- main theorem
mutual
  -- 任意のCPSの値 v,w について v→w ならば、v♮ → w♮
  correctV : {var : DS.Ty  Set}  {τ : CPS.Ty}  {β : DS.Ty}  {σβ : DS.Mc} 
             {v w : CPS.value[ var  dsT ] τ} 
             CPS.ReduceV v w 
             DS.Reduce {var} {β} {σβ = σβ} (DS.Val (dsV v)) (DS.Val (dsV w))
  correctV {w = w} CPS.REtaV = DS.REtaV (dsV w)
  correctV (CPS.RFun red) = DS.RFun  x  correctE (red x))
  correctV CPS.RId = DS.RId
  correctV (CPS.RTrans red-v₁ red-v₂) =
    DS.RTrans (correctV red-v₁) (correctV red-v₂)
  
  -- 任意のCPS項 e,e' について e→e' ならば、e# → e'#
  correctE : {var : DS.Ty  Set} {Δ : CPS.Delta} {β : CPS.Ty} {σβ : CPS.Mc} 
             {e e' : CPS.term[ var  dsT , Δ , σβ ]⇒ β} 
             CPS.Reduce e e' 
             DS.Reduce {var} (dsE e) (dsE e')
  correctE (CPS.RBetaV ΔΘ {e₁} {k = c} {m} {e₁'} {e₁''} {e₂} sub csub msub) = begin
    (DS.plugM (dsM ΔΘ m)
       (DS.plug (dsC c)
        (DS.NonVal (DS.App (DS.Val (DS.Fun  x  dsE (e₁ x)))) (DS.Val _)))))
    ⟶⟨ DS.reducePlugM (dsM ΔΘ m)
                   (DS.reducePlug (dsC c) (DS.RBetaV _ _ _ (lemma-Subst sub))) 
    DS.plugM (dsM ΔΘ m) (DS.plug (dsC c) (dsE e₁'))
    ⟶⟨ DS.reducePlugM (dsM ΔΘ m) (lemma-CSubst csub) 
    DS.plugM (dsM ΔΘ m) (dsE e₁'')
    ≡⟨ lemma-MSubst ΔΘ refl msub 
    dsE e₂
    
    where open DS.Reasoning
  correctE (CPS.RBetaLet ΔΘ sub msub) = redBetaLet ΔΘ sub msub 
  correctE (CPS.RShift id₁ id₂ {w} {j} {CPS.GCons ΔΘ c m}) =
    DS.reducePlugM (dsM ΔΘ m)
      (DS.reducePlug (dsC c)
                     (DS.RShift (ds-id-cont-type id₁) (ds-id-cont-type id₂)
                                (dsV w) (dsC j)))
  correctE (CPS.RShift0 ΔΘ id {w} {j} {c} {m}) =
    DS.reducePlugM (dsM ΔΘ m)
      (DS.reducePlug (dsC c)
                     (DS.RShift0 (ds-id-cont-type id) (dsV w) (dsC j)))
  correctE (CPS.RReset ΔΘ {v} {c} {m}) = 
    DS.reducePlugM (dsM ΔΘ m) (DS.reducePlug (dsC c) (DS.RReset (dsV v)))
  correctE (CPS.RVal₁ ΔΘ {m = m} red-c) = DS.reducePlugM (dsM ΔΘ m) (correctC red-c)
  correctE (CPS.RVal₂ ΔΘ {k = c} {m = m} red-v) =
    DS.reducePlugM (dsM ΔΘ m) (DS.reducePlug (dsC c) (correctV red-v))
  correctE (CPS.RVal₃ ΔΘ red-m) = correctM ΔΘ red-m
  correctE (CPS.RApp₁ ΔΘ {k = c} {m} red-v) = 
    DS.reducePlugM (dsM ΔΘ m) (DS.reducePlug (dsC c) (DS.RApp₁ (correctV red-v)))
  correctE (CPS.RApp₂ ΔΘ {k = c} {m} red-v) = 
    DS.reducePlugM (dsM ΔΘ m) (DS.reducePlug (dsC c) (DS.RApp₂ (correctV red-v)))
  correctE (CPS.RApp₃ ΔΘ {m = m} red-c) = DS.reducePlugM (dsM ΔΘ m) (correctC red-c)
  correctE (CPS.RApp₄ ΔΘ red-m) = correctM ΔΘ red-m
  correctE CPS.RId = DS.RId
  correctE (CPS.RTrans red₁ red₂) = DS.RTrans (correctE red₁) (correctE red₂)
  
  -- CPSの継続 c,c' について c→c' ならば、c♭[e] → c'♭[e]
  correctC : {var : DS.Ty  Set} {Δ : CPS.Delta} 
              {τ α β : CPS.Ty} {σ σα : CPS.Mc} 
              {c c' : CPS.cont[ var  dsT , Δ ] (τ CPS.⇒ σα  α)} 
              {e : DS.term[ var , dsT τ DS.▷⟨ dsMc σα  dsT α ]⟨ dsMc σ  dsT β} 
              CPS.ReduceC c c' 
              DS.Reduce (DS.plug (dsC c) e) (DS.plug (dsC c') e)
  correctC {c' = CPS.KVar} {e} CPS.REtaLet = DS.REtaLet e
  correctC {c' = CPS.KId id} {e} CPS.REtaLet = DS.REtaLet e
  correctC {Δ = CPS.K (τ CPS.⇒ σα  α)} {c' = CPS.KLet e} CPS.REtaLet = 
    DS.RLet₂  x  DS.RBetaLet _ _ _ (lemma-Subst {e₁ = e} lemma-Var-subst))
  correctC {Δ = CPS.• (γ CPS.⇒ σid  γ') id} {c' = CPS.KLet e} CPS.REtaLet =
    DS.RLet₂  x  DS.RBetaLet _ _ _ (lemma-Subst {e₁ = e} lemma-Var-subst))
  correctC {Δ = CPS.K (τ CPS.⇒ σα  α)} (CPS.RKLet red) =
    DS.RLet₂  x  correctE (red x))
  correctC {Δ = CPS.• (γ CPS.⇒ σid  γ') id} (CPS.RKLet red) =
    DS.RLet₂  x  correctE (red x))
  correctC CPS.RId = DS.RId
  correctC (CPS.RTrans red-c₁ red-c₂) =
    DS.RTrans (correctC red-c₁) (correctC red-c₂)

  -- CPSのメタ継続 m,m' について m→m' ならば、m♭♭[e] → m'♭♭[e]
  correctM : {var : DS.Ty  Set} {Δ : CPS.Delta} {Θ : CPS.Theta} 
             {β : CPS.Ty} {σ σβ : CPS.Mc} 
             (ΔΘ : CPS.Delta-Theta Δ Θ) 
             {m m' : CPS.mcont[ var  dsT , Θ , σβ ] σ} 
             {e : DS.term[ var , dsΔ Δ ]⟨ dsMc σ  dsT β} 
             CPS.ReduceM m m' 
             DS.Reduce (DS.plugM (dsM ΔΘ m) e) (DS.plugM (dsM ΔΘ m') e)
  correctM {Δ = CPS.• (γ CPS.⇒ σid  γ') id}
           tt (CPS.RGCons₁ {Δ' = τ CPS.⇒ σα  α} ΔΘ {m = m} red-c) =
    DS.reducePlugM (dsM ΔΘ m) (correctC red-c)
  correctM {Δ = CPS.• (γ CPS.⇒ σid  γ') id}
           tt (CPS.RGCons₂ {Δ' = τ CPS.⇒ σα  α} ΔΘ red-m) = correctM ΔΘ red-m