Source code on Github
{-# OPTIONS --allow-unsolved-metas #-}
open import Prelude.Init; open SetAsType
open import Prelude.General
open Integer using () renaming (_-_ to _-ℤ_; _+_ to _+ℤ_)
open import Prelude.DecEq
open import Prelude.Sets
open import Prelude.Maps.Abstract hiding (; singleton) renaming (_∪_ to _∪ᵐ_)
open CommandDSL
open import Prelude.Lists
open import Prelude.Apartness
open import Prelude.Semigroup
open import Prelude.Monoid

module Deep.Ledger
  (Part : Type) -- a fixed set of participants
   _ : DecEq Part 
  where

instance _ = Semigroup-ℤ-+; _ = SemigroupLaws-ℤ-+; _ = Monoid-ℤ-+; _ = MonoidLaws-ℤ-+

-- The state of a ledger is a collection of participants, along with their balance.
S : Type
S = Map⟨ Part   

-- A transaction is transferring money from one participant to another
data Tx : Type where
  _—→⟨_⟩_ : Part    Part  Tx

-- A ledger is a list of transactions
L = List Tx

variable
  s s′ s″ s₁ s₂ : S
  t t′ t″ : Tx
  l l′ l″ l₁ l₂ : L
  ls ls′ ls″ : L × S

-- ** Denotational semantics

Domain = S  S

record Denotable (A : Type) : Type where
  field
    ⟦_⟧ : A  Domain
open Denotable {{...}} public

instance
  ⟦Tx⟧ : Denotable Tx
  ⟦Tx⟧ .⟦_⟧ (p₁ —→⟨ n  p₂) s = modify p₂ (_+ℤ n) $ modify p₁ (_-ℤ n) s

  ⟦L⟧ : Denotable L
  ⟦L⟧ .⟦_⟧ []      = id
  ⟦L⟧ .⟦_⟧ (t  l) =  l    t 

comp :  x   l ++ l′  x  ( l′    l ) x
comp {l = []}    {l′} x = refl
comp {l = t  l} {l′} x rewrite comp {l}{l′} ( t  x) = refl

-- ** Operational semantics

infix 0 _—→_ _—→⋆_ _—→⋆′_

data _—→_ : L × S  L × S  Type where
  singleStep :
     ------------------------
     t  l , s —→ l ,  t  s

data _—→′_ : L × S  S  Type where
  finalStep :
      --------------
      ([] , s) —→′ s

data _—→⋆_ : L × S  L × S  Type where
   base :
       ---------
       ls —→⋆ ls

   step :
       ls —→ ls′
      ls′ —→⋆ ls″
       ----------
      ls —→⋆ ls″

_—→⋆′_ : L × S  S  Type
ls —→⋆′ s = ls —→⋆ ([] , s)

comp′ :
    l       , s  —→⋆′ s′
   l′      , s′ —→⋆′ s″
   l ++ l′ , s  —→⋆′ s″
comp′ {l = []}    base                   s′→s″ = s′→s″
comp′ {l = _  _} (step singleStep s→s′) s′→s″ = step singleStep (comp′ s→s′ s′→s″)

oper-base⋆ : l , s —→⋆′  l  s
oper-base⋆ {l = []}    = base
oper-base⋆ {l = _  _} = step singleStep oper-base⋆

-- ** Relating denotational and operational semantics

denot⇔oper : ( l  s  s′)  (l , s —→⋆′ s′)
denot⇔oper = denot→oper , oper→denot
  where
    denot→oper : ( l  s  s′)  (l , s —→⋆′ s′)
    denot→oper {l = []}    refl = base
    denot→oper {l = _  _} refl = step singleStep (denot→oper refl)

    oper→denot : (l , s —→⋆′ s′)  ( l  s  s′)
    oper→denot {l = .[]}   base                = refl
    oper→denot {l = _  _} (step singleStep p) = oper→denot p

-- ** Axiomatic semantics

Predˢ = Pred S 0ℓ
{-
-- the shallow embedding of predicates seems to break here..
-- ..we really need to get ahold of the actual variables, i.e. from a deeply-embedded DSL
fv : Predˢ → Set⟨ Part ⟩
fv P = {!!}
-}

data Assertion : Type where
  `emp `⊥ : Assertion
  -- _`≡_ : ℤ → ℤ → Assertion
  _`↦_ : Part    Assertion
  _`∗_ _`—∗_ : Assertion  Assertion  Assertion
  _`∘_ : Assertion  (S  S)  Assertion

infixr 9 _`∘_

fv : Assertion  Set⟨ Part 
fv `emp      = 
fv `⊥        = 
-- fv (_ `≡ _) = ∅
fv (p `↦ _)  = singleton p
fv (P `∗ Q)  = fv P  fv Q
fv (P `—∗ Q) = fv P  fv Q
fv (P `∘ _)  = fv P

emp : Predˢ
emp s =  k  k ∉ᵈ s

_♯_←_ : S  S  S  Type
s₁  s₂  s =  s₁  s₂ ⟩≡ s

_∗_ : Predˢ  Predˢ  Predˢ
(P  Q) s =  λ s₁   λ s₂  (s₁  s₂  s) × P s₁ × Q s₂

_—∗_ : Predˢ  Predˢ  Predˢ
(P —∗ Q) s =  s′  s′  s  P s′  Q (s ∪ᵐ s′)

⟦_⟧ᵖ : Assertion  Predˢ
 `emp    ⟧ᵖ = emp
 `⊥      ⟧ᵖ = const 
-- ⟦ x `≡ y  ⟧ᵖ = {!!}
 p `↦ n  ⟧ᵖ = _[ p  n ]∅
 P `∗ Q  ⟧ᵖ =  P ⟧ᵖ   Q ⟧ᵖ
 P `—∗ Q ⟧ᵖ =  P ⟧ᵖ —∗  Q ⟧ᵖ
 P `∘ f  ⟧ᵖ =  P ⟧ᵖ  f

infix 1 _`⊢_
_`⊢_ : Assertion  Assertion  Type
P `⊢ Q =  P ⟧ᵖ   Q ⟧ᵖ

_∙_ : Assertion  S  Type
P  s =  P ⟧ᵖ s

variable
  P P′ P₁ P₂ Q Q′ Q₁ Q₂ R : Assertion

data ⟨_⟩_⟨_⟩ : Assertion  L  Assertion  Type₁ where

  base :
    --
    ------------
     P  []  P 
  --   -------------------------
  --   ⟨ P ∘ ⟦ t ⟧ ⟩ [ t ] ⟨ P ⟩

  step :
       P  l  R 
      -------------------------
      P `∘  t   t  l  R 
  --     ⟨ P ⟩ l  ⟨ Q ⟩
  --   → ⟨ Q ⟩ l′ ⟨ R ⟩
  --     -------------------
  --   → ⟨ P ⟩ l ++ l′ ⟨ R ⟩

  weaken-strengthen :

      P′ `⊢ P
     Q  `⊢ Q′
      P   l  Q  
      ---------------
      P′  l  Q′ 

-- utilities
axiom-base⋆ :  P `∘  l   l  P 
axiom-base⋆ {P = P} {l = []}    = weaken-strengthen {P = P} id id base
axiom-base⋆ {P = P} {l = t  l} = weaken-strengthen {P = (P `∘  l ) `∘  t } id id (step axiom-base⋆)

⟦⟧-comm : ( t    t′ ) s  ( t′    t ) s
⟦⟧-comm {t = A —→⟨ n  B}{t′ = A′ —→⟨ n′  B′} = {!!}

denot-comm : ( t    l ) s  ( l    t ) s
denot-comm {t = t}{l = []}    {s} = refl
denot-comm {t = t}{l = t′  l}{s}
  rewrite sym $ denot-comm {t′}{l}{s}
        | sym $ denot-comm {t′}{l}{ t  s}
        | ⟦⟧-comm {t}{t′}{ l  s}
        | denot-comm {t}{l}{s}
        | denot-comm {t}{l}{ t′  s}
        = refl

-- equivalences
axiom⇔denot :  P  l  Q   (P `⊢ Q `∘  l )
axiom⇔denot = axiom→denot , denot→axiom
  where
    axiom→denot :  P  l  Q   (P `⊢ Q `∘  l )
    axiom→denot base                              Ps = Ps
    axiom→denot (step PlQ)                        = axiom→denot PlQ
    axiom→denot (weaken-strengthen P⊢P′ Q′⊢Q PlQ) = Q′⊢Q  axiom→denot PlQ  P⊢P′

    denot→axiom : (P `⊢ Q `∘  l )   P  l  Q 
    denot→axiom {P = P} {Q = Q} {l = []}    H
      = weaken-strengthen {P = P} {Q = P} {Q′ = Q} id H base
    denot→axiom {P = P} {Q = Q} {l = t  l} H
      = weaken-strengthen {P′ = P} {P = Q `∘  t  l } {Q = Q} {Q′ = Q} H id (axiom-base⋆ {P = Q} {l = t  l})

axiom⇔oper :  P  l  Q   (∀ {s s′}  P  s  l , s —→⋆′ s′  Q  s′)
axiom⇔oper
  {- ** 1. proving from scratch -}
  -- = axiom→oper , oper→axiom
  -- where
  --   axiom→oper : ⟨ P ⟩ l ⟨ Q ⟩ → (∀ {s s′} → P s → l , s —→⋆′ s′ → Q s′)
  --   axiom→oper base                              Ps base                   = Ps
  --   axiom→oper (step PlQ)                        Ps (step singleStep s→s′) = axiom→oper PlQ Ps s→s′
  --   axiom→oper (weaken-strengthen P⊢P′ Q′⊢Q PlQ) Ps s→s′                   = Q′⊢Q $ axiom→oper PlQ (P⊢P′ Ps) s→s′

  --   oper→axiom : (∀ {s s′} → P s → l , s —→⋆′ s′ → Q s′) → ⟨ P ⟩ l ⟨ Q ⟩
  --   oper→axiom {l = []}    H = weaken-strengthen id (flip H base) base
  --   oper→axiom {l = _ ∷ _} H = weaken-strengthen (λ Ps → H Ps oper-base⋆) id axiom-base⋆

  {- ** 2. composing axiom⇔denot ∘ denot⇔oper -}
  = (λ{ P⊢ Ps s→s′  subst _ (proj₂ denot⇔oper s→s′) (P⊢ Ps)})  proj₁ axiom⇔denot
  , λ H  proj₂ axiom⇔denot λ Ps  H Ps oper-base⋆


-- ** Separation logic

mod : L  Set⟨ Part 
mod [] = 
mod (p₁ —→⟨ _  p₂  l) = singleton p₁  singleton p₂  mod l

-- ⟦⟧-constᵗ : dom (⟦ t ⟧ s) ≡ dom s
-- ⟦⟧-constᵗ {t = p —→⟨ n ⟩ p′}    = refl

-- ⟦⟧-const : ∀ {s} {l : L} → dom (⟦ l ⟧ s) ≡ dom s
-- ⟦⟧-const {s = _} {l = []}    = refl
-- ⟦⟧-const {s = s} {l = t ∷ l} rewrite ⟦⟧-const {⟦ t ⟧ s}{l} = ⟦⟧-constᵗ {t}{s}

⟦⟧-union :
     s₁  s₂ ⟩≡ s
    --------------------------------------
     l  s₁   l  s₂ ⟩≡  l  s
⟦⟧-union s₁⊎s₂ = {!!} , {!!}

postulate
  ⟦⟧-♯ :
      s₁  s₂  s
      -----------------------------
      l  s₁   l  s₂   l  s

-- update-emptyᵗ : proj₁ s ≡ ∅ → ⟦ t ⟧ s ≡ s
-- update-emptyᵗ {.(⟨ [] ⟩∶- _) , snd} {x —→⟨ x₁ ⟩ x₂} refl = {!!}

-- update-empty : proj₁ s ≡ ∅ → ⟦ l ⟧ s ≡ s
-- update-empty {s}{[]}    refl = refl
-- update-empty {s}{t ∷ l} refl rewrite update-emptyᵗ {s}{t} refl = {!!}
-- rewrite update-empty {⟦ t ⟧ s}{l} (update-emptyᵗ {s}{t} refl) = refl

frame :
    mod l  fv R
   R  s
    -----------
   R   l  s
frame = {!!}
-- frame {l} {`emp}    {.(⟨ [] ⟩∶- _) , _} _ refl = subst (`emp ∙_) (sym $ update-empty {l = l} refl) refl
-- frame {l} {p `↦ v} {s} mod♯ (p∈ , p≡) = {!!}
-- frame {l} {P `∗ Q}  {s} mod♯ Rs = {!!}
-- frame {l} {P `—∗ Q} {s} mod♯ Rs = {!!}
-- frame {l} {P `∘ f}  {s} mod♯ Rs = {!!}
-- frame {[]} {R} {s} mod♯fv Rs = Rs
-- frame {(p —→⟨ n ⟩ p′) ∷ l} {R} {s} mod♯fv Rs = {!!}

-- need deeply-embedded Predˢ for fv
[FRAME] :
     P  l  Q 
   mod l  fv R
    -----------------------
    P `∗ R  l  Q `∗ R 
[FRAME] {P}{l}{Q}{R} PlQ mod♯fv = proj₂ axiom⇔denot d
  where
    d : (P `∗ R) `⊢ (Q `∗ R) `∘  l 
    d {s} (s₁ , s₂ , s₁♯s₂ , Ps₁ , Rs₂) =  l  s₁ ,  l  s₂ , p , Qs₁′ , Rs₂′
    {-
      s = s₁ ⊎ s₂
      —→ ⟦l⟧s = ⟦l⟧s₁ ⊎ ⟦l⟧s₂
      P s₁
      —→ Q ⟦l⟧s₁
      R s₂
      —→ R ⟦l⟧s₂

         ⟦l⟧s = ⟦l⟧s₁ ⊎ ⟦l⟧s₂     Q ⟦l⟧s₁      R ⟦l⟧s₂
      ----------------------------------------------------
                          (Q ∗ R) ⟦l⟧s
    -}
      where
        Qs₁′ : Q   l  s₁
        Qs₁′ = proj₁ axiom⇔denot PlQ Ps₁

        Rs₂′ : R   l  s₂
        Rs₂′ = frame {l = l} {R = R} {s = s₂} mod♯fv Rs₂

        p :  l  s₁   l  s₂   l  s
        p = ⟦⟧-♯ {s₁}{s₂}{s}{l} s₁♯s₂
{-

-- ** Concurrent separation logic
open import Data.List.Relation.Ternary.Interleaving
_∥_←_ : L → L → L → Type
l₁ ∥ l₂ ← l = Interleaving _≡_ _≡_ l₁ l₂ l

h :
    s₁ ♯ s₂ ← s
  → l₁ ∥ l₂ ← l
  → mod l₁ S.♯ mod l₂
    -------------------------------
  → ⟦ l₁ ⟧ s₁ ♯ ⟦ l₂ ⟧ s₂ ← ⟦ l ⟧ s
h {s₁}{s₂}{s}{l₁}{l₂}{l} s₁♯s₂ l₁∥l₂ l₁♯l₂ = h₁ , h₂
  where
    ps₁ = proj₁ (⟦ l₁ ⟧ s₁)
    ps₂ = proj₁ (⟦ l₂ ⟧ s₂)

    All∉ : All (_∉′ ps₂) (list ps₁)
    All∉ = {!!}

    h₁ : ⟦ l₁ ⟧ s₁ ♯ ⟦ l₂ ⟧ s₂
    h₁ = let p = L.filter-none (_∈′? ps₂) {xs = list ps₁} All∉ in {!!} -- subst _ p refl

    h₂ : ⟦ l ⟧ s ≡ᵐ union (⟦ l₁ ⟧ s₁) (⟦ l₂ ⟧ s₂)
    h₂ = {!!}

[INTERLEAVE] :
    l₁ ∥ l₂ ← l
  → ⟨ P₁ ⟩ l₁ ⟨ Q₁ ⟩
  → ⟨ P₂ ⟩ l₂ ⟨ Q₂ ⟩
  → mod l₁ S.♯ mod l₂
  -- → fv P₁ ∪ fv Q₁ S.♯ mod l₂
  -- → fv P₂ ∪ fv Q₂ S.♯ mod l₁
    ---------------------------
  → ⟨ P₁ `∗ P₂ ⟩ l ⟨ Q₁ `∗ Q₂ ⟩

[INTERLEAVE] {l₁}{l₂}{l}{P₁}{Q₁}{P₂}{Q₂} l₁∥l₂ PlQ PlQ′ l₁♯l₂ = proj₂ axiom⇔denot d
  where
    d : (P₁ `∗ P₂) `⊢ (Q₁ `∗ Q₂) `∘ ⟦ l ⟧
    d {s} (s₁ , s₂ , s₁♯s₂ , Ps₁ , Ps₂) = _ , _ , q , q₁ , q₂
      where
        q₁ : Q₁ ∙ ⟦ l₁ ⟧ s₁
        q₁ = proj₁ axiom⇔denot PlQ Ps₁

        q₂ : Q₂ ∙ ⟦ l₂ ⟧ s₂
        q₂ = proj₁ axiom⇔denot PlQ′ Ps₂

        q : ⟦ l₁ ⟧ s₁ ♯ ⟦ l₂ ⟧ s₂ ← ⟦ l ⟧ s
        q = {!!} -- h s₁♯s₂ l₁∥l₂ l₁♯l₂
-}