-- A simplified version of the monad reification trick presented in Section 2.

module BiGUL.CompSeq where

open import BiGUL.Utilities
open import BiGUL.Partiality hiding (_↦_)

open import Data.Product
open import Data.Sum
open import Data.Bool
open import Relation.Binary.PropositionalEquality


infix 0 _↦_ _/↦

mutual

  _↦_ : {A : Set} → Par A → A → Set
  return x             ↦ x' = x ≡ x'
  mx >>= f             ↦ y  = ∃ λ x → (mx ↦ x) × (f x ↦ y)
  fail                 ↦ x  = ⊥
  catch mx f my        ↦ y  = (∃ λ x → (mx ↦ x) × (f x ↦ y)) ⊎ ((mx /↦) × (my ↦ y))
  assert     b then mx ↦ x  = (b ≡ true ) × (mx ↦ x)   
  assert-not b then mx ↦ x  = (b ≡ false) × (mx ↦ x)   

  _/↦ : {A : Set} → Par A → Set
  return x             /↦ = ⊥
  mx >>= f             /↦ = (mx /↦) ⊎ (∃ λ x → (mx ↦ x) × (f x /↦))
  fail                 /↦ = ⊤
  catch mx f my        /↦ = (∃ λ x → (mx ↦ x) × (f x /↦)) ⊎ ((mx /↦) × (my /↦))
  assert     b then mx /↦ = (b ≡ false) ⊎ ((b ≡ true ) × (mx /↦))
  assert-not b then mx /↦ = (b ≡ true ) ⊎ ((b ≡ false) × (mx /↦))

record Lens (S V : Set) : Set₁ where
  field
    put  : S → V → Par S
    get  : S → Par V
    PutGet  : {s s' : S} {v : V} → (put s v ↦ s') → (get s' ↦ v)
    GetPut  : {s : S} {v : V} → (get s ↦ v) → (put s v ↦ s)

_⇆_ : Set → Set → Set₁
S ⇆ V = Lens S V

_↔_ : {A B C : Set} → A ⇆ B → B ⇆ C → A ⇆ C
l ↔ r = record
  {  put  = λ a c → Lens.get l a >>= λ b → Lens.put r b c >>= Lens.put l a
  ;  get  = λ a → Lens.get l a >>= Lens.get r
  ;  PutGet  = λ { (b , get-l-a↦b , b' , put-r-b↦b' , put-l-a-b'↦a') →
                   b' , Lens.PutGet l put-l-a-b'↦a' , Lens.PutGet r put-r-b↦b' }
  ;  GetPut  = λ { (b , get-l-a↦b , get-r-b↦c) →
                   b , get-l-a↦b , b , Lens.GetPut r get-r-b↦c , Lens.GetPut l get-l-a↦b } }