------------------------------------------------------------------------
-- INCREMENTAL λ-CALCULUS
--
-- Change evaluation (Def 3.6 and Fig. 4h).
------------------------------------------------------------------------

import Parametric.Syntax.Type as Type
import Parametric.Syntax.Term as Term
import Parametric.Denotation.Value as Value
import Parametric.Denotation.Evaluation as Evaluation
import Parametric.Change.Validity as Validity

module Parametric.Change.Specification
    {Base : Type.Structure}
    (Const : Term.Structure Base)
    (⟦_⟧Base : Value.Structure Base)
    (⟦_⟧Const : Evaluation.Structure Const ⟦_⟧Base)
    (validity-structure : Validity.Structure ⟦_⟧Base)
  where

open Type.Structure Base
open Term.Structure Base Const
open Value.Structure Base ⟦_⟧Base
open Evaluation.Structure Const ⟦_⟧Base ⟦_⟧Const
open Validity.Structure ⟦_⟧Base validity-structure

open import Base.Denotation.Notation
open import Relation.Binary.PropositionalEquality
open import Theorem.CongApp
open import Postulate.Extensionality

-- This module defines two extension points, so to avoid some of
-- the boilerplate, we use record notation.

record Structure : Set₁ where
  ----------------
  -- Parameters --
  ----------------

  field
    -- Extension point 1: Derivatives of constants.
    ⟦_⟧ΔConst :  {Σ τ}  (c  : Const Σ τ) (ρ :  Σ )  Δ₍ Σ  ρ  Δ₍ τ  ( c ⟧Const ρ)

    -- Extension point 2: Correctness of the instantiation of extension point 1.
    correctness-const :  {Σ τ} (c : Const Σ τ) 
      Derivative₍ Σ , τ   c ⟧Const  c ⟧ΔConst

  ---------------
  -- Interface --
  ---------------

  -- We provide: Derivatives of terms and lists of terms.
  ⟦_⟧Δ :  {τ Γ}  (t : Term Γ τ) (ρ :  Γ ) ( : Δ₍ Γ  ρ)  Δ₍ τ  ( t  ρ)
  ⟦_⟧ΔTerms :  {Σ Γ}  (ts : Terms Γ Σ) (ρ :  Γ ) ( : Δ₍ Γ  ρ)  Δ₍ Σ  ( ts ⟧Terms ρ)

  -- And we provide correctness proofs about the derivatives.
  correctness :  {τ Γ} (t : Term Γ τ) 
    Derivative₍ Γ , τ   t   t ⟧Δ

  correctness-terms :  {Σ Γ} (ts : Terms Γ Σ) 
    Derivative₍ Γ , Σ   ts ⟧Terms  ts ⟧ΔTerms

  --------------------
  -- Implementation --
  --------------------

  ⟦_⟧ΔVar :  {τ Γ}  (x : Var Γ τ)  (ρ :  Γ )  Δ₍ Γ  ρ  Δ₍ τ  ( x ⟧Var ρ)
   this   ⟧ΔVar (v  ρ) (dv  ) = dv
   that x ⟧ΔVar (v  ρ) (dv  ) =  x ⟧ΔVar ρ 

  ⟦_⟧Δ (const c ts) ρ  =  c ⟧ΔConst ( ts ⟧Terms ρ) ( ts ⟧ΔTerms ρ )
  ⟦_⟧Δ (var x) ρ  =  x ⟧ΔVar ρ 
  ⟦_⟧Δ (app {σ} {τ} s t) ρ  =
       call-change {σ} {τ} ( s ⟧Δ ρ ) ( t  ρ) ( t ⟧Δ ρ )
  ⟦_⟧Δ (abs {σ} {τ} t) ρ  = cons
     v dv   t ⟧Δ (v  ρ) (dv  ))
     v dv 
      begin
         t  (v ⊞₍ σ  dv  ρ)  ⊞₍ τ 
         t ⟧Δ (v ⊞₍ σ  dv  ρ) (nil₍ σ  (v ⊞₍ σ  dv)  )
      ≡⟨  correctness t (v ⊞₍ σ  dv  ρ) (nil₍ σ  (v ⊞₍ σ  dv)  ) 
         t  (after-env (nil₍ σ  (v ⊞₍ σ  dv)  ))
      ≡⟨⟩
         t  (((v ⊞₍ σ  dv) ⊞₍ σ  nil₍ σ  (v ⊞₍ σ  dv))  after-env )
      ≡⟨  cong  hole   t  (hole  after-env )) (update-nil₍ σ  (v ⊞₍ σ  dv))  
         t  (v ⊞₍ σ  dv  after-env )
      ≡⟨⟩
         t  (after-env (dv  ))
      ≡⟨  sym (correctness t (v  ρ) (dv  ))  
         t  (v  ρ)  ⊞₍ τ    t ⟧Δ (v  ρ) (dv  )
      ) where open ≡-Reasoning

    ⟧ΔTerms ρ  = 
   t  ts ⟧ΔTerms ρ  =  t ⟧Δ ρ    ts ⟧ΔTerms ρ 

  correctVar :  {τ Γ} (x : Var Γ τ) 
    Derivative₍ Γ , τ   x   x ⟧ΔVar
  correctVar (this) (v  ρ) (dv  ) = refl
  correctVar (that y) (v  ρ) (dv  ) = correctVar y ρ 

  correctness-terms  ρ  = refl
  correctness-terms (t  ts) ρ  =
    cong₂ _•_
      (correctness t ρ )
      (correctness-terms ts ρ )

  correctness (const {Σ} {τ} c ts) ρ  =
    begin
      after₍ τ  ( c ⟧ΔConst ( ts ⟧Terms ρ) ( ts ⟧ΔTerms ρ ))
    ≡⟨ correctness-const c ( ts ⟧Terms ρ) ( ts ⟧ΔTerms ρ ) 
       c ⟧Const (after-env ( ts ⟧ΔTerms ρ ))
    ≡⟨ cong  c ⟧Const (correctness-terms ts ρ ) 
       c ⟧Const ( ts ⟧Terms (after-env ))
     where open ≡-Reasoning
  correctness {τ} (var x) ρ  = correctVar {τ} x ρ 
  correctness (app {σ} {τ} s t) ρ  =
    let
      f =  s  ρ
      g =  s  (after-env )
      u =  t  ρ
      v =  t  (after-env )
      Δf =  s ⟧Δ ρ 
      Δu =  t ⟧Δ ρ 
    in
      begin
        f u ⊞₍ τ  call-change {σ} {τ} Δf u Δu
      ≡⟨  sym (is-valid {σ} {τ} Δf u Δu) 
        (f ⊞₍ σ  τ  Δf) (u ⊞₍ σ  Δu)
      ≡⟨ correctness {σ  τ} s ρ  ⟨$⟩ correctness {σ} t ρ  
        g v
       where open ≡-Reasoning
  correctness {σ  τ} {Γ} (abs t) ρ  = ext  v 
    let
      -- dρ′ : ΔEnv (σ • Γ) (v • ρ)
      dρ′ = nil₍ σ  v  
    in
      begin
         t  (v  ρ) ⊞₍ τ   t ⟧Δ _ dρ′
      ≡⟨ correctness {τ} t _ dρ′ 
         t  (after-env dρ′)
      ≡⟨ cong  hole   t  (hole  after-env )) (update-nil₍ σ  v) 
         t  (v  after-env )
      
    ) where open ≡-Reasoning

  -- Corollary: (f ⊞ df) (v ⊞ dv) = f v ⊞ df v dv

  corollary :  {σ τ Γ}
    (s : Term Γ (σ  τ)) (t : Term Γ σ) (ρ :  Γ ) ( : Δ₍ Γ  ρ) 
      ( s  ρ ⊞₍ σ  τ   s ⟧Δ ρ )
        ( t  ρ ⊞₍ σ   t ⟧Δ ρ )
     ( s  ρ) ( t  ρ)
      ⊞₍ τ 
      (call-change {σ} {τ} ( s ⟧Δ ρ )) ( t  ρ) ( t ⟧Δ ρ )

  corollary {σ} {τ} s t ρ  =
    is-valid {σ} {τ} ( s ⟧Δ ρ ) ( t  ρ) ( t ⟧Δ ρ )

  corollary-closed :  {σ τ} (t : Term  (σ  τ))
    (v :  σ ) (dv : Δ₍ σ  v)
      t   (after₍ σ  dv)
      t   v ⊞₍ τ  call-change {σ} {τ} ( t ⟧Δ  ) v dv

  corollary-closed {σ} {τ} t v dv =
    let
      f  =  t  
      Δf =  t ⟧Δ  
    in
      begin
        f (after₍ σ  dv)
      ≡⟨ cong  hole  hole (after₍ σ  dv))
              (sym (correctness {σ  τ} t  )) 
         (f ⊞₍ σ  τ  Δf) (after₍ σ  dv)
      ≡⟨ is-valid {σ} {τ} ( t ⟧Δ  ) v dv 
        f (before₍ σ  dv) ⊞₍ τ  call-change {σ} {τ} Δf v dv
       where open ≡-Reasoning