module DynamicallyChecked.Case (S V : Set) where
open import DynamicallyChecked.Partiality
open import DynamicallyChecked.Utilities
open import DynamicallyChecked.Lens
open import Agda.Primitive
open import Function
open import Data.Product
open import Data.Bool
open import Data.List
open import Relation.Binary.PropositionalEquality
data BranchType : Set₁ where
normal : (S ⇆ V) → (S → Bool) → BranchType
adaptive : (S → V → S) → BranchType
elimBranchType : {l : Level} {A : Set l} → ((S ⇆ V) → (S → Bool) → A) → ((S → V → S) → A) → BranchType → A
elimBranchType g h (normal l q) = g l q
elimBranchType g h (adaptive f) = h f
isNormal : BranchType → Bool
isNormal = elimBranchType (λ _ _ → true) (λ _ → false)
Branch : Set₁
Branch = (S → V → Bool) × BranchType
check-diversion : List Branch → S → V → Par ⊤
check-diversion [] s v = return tt
check-diversion ((p , normal l q) ∷ bs) s v = assert-not p s v then assert-not q s then check-diversion bs s v
check-diversion ((p , adaptive f) ∷ bs) s v = assert-not p s v then check-diversion bs s v
put-with-adaptation : List Branch → List Branch → S → V → (S → Par S) → Par S
put-with-adaptation [] bs' s v cont = fail
put-with-adaptation ((p , b) ∷ bs) bs' s v cont =
if p s v then elimBranchType (λ l q → Lens.put l s v >>= λ s' →
assert p s' v then assert q s' then
check-diversion bs' s' v >> return s')
(λ f → cont (f s v)) b
else put-with-adaptation bs ((p , b) ∷ bs') s v cont
put : List Branch → S → V → Par S
put bs s v = put-with-adaptation bs [] s v (λ s' → put-with-adaptation bs [] s' v (const fail))
fail-continuation : (bs bs' : List Branch) {s' s : S} {v : V} → put-with-adaptation bs bs' s v (const fail) ↦ s' →
{cont : S → Par S} → put-with-adaptation bs bs' s v cont ↦ s'
fail-continuation [] bs' ()
fail-continuation ((p , b) ∷ bs) bs' {s = s} {v} c with p s v
fail-continuation ((p , b) ∷ bs) bs' c | false = fail-continuation bs ((p , b) ∷ bs') c
fail-continuation ((p , normal l q) ∷ bs) bs' c | true = c
fail-continuation ((p , adaptive f) ∷ bs) bs' () | true
get : List Branch → S → Par V
get [] s = fail
get ((p , normal l q) ∷ bs) s = if q s then (Lens.get l s >>= λ v → assert p s v then return v)
else (get bs s >>= λ v → assert-not p s v then return v)
get ((p , adaptive f) ∷ bs) s = get bs s >>= λ v → assert-not p s v then return v
get-revcat : (bs : List Branch) {s : S} {v : V} (bs' : List Branch) → check-diversion bs' s v ↦ tt →
get bs s ↦ v → get (revcat bs' bs) s ↦ v
get-revcat bs [] _ get↦ = get↦
get-revcat bs ((p , normal l q) ∷ bs') (assert-not p-s-v≡false then assert-not q-s≡false then check-diversion↦) get↦
with get-revcat ((p , normal l q) ∷ bs) bs' check-diversion↦
get-revcat bs ((p , normal l q) ∷ bs') (assert-not p-s-v≡false then assert-not q-s≡false then check-diversion↦) get↦
| k rewrite q-s≡false = k (get↦ >>= assert-not p-s-v≡false then return refl)
get-revcat bs ((p , adaptive f) ∷ bs') (assert-not p-s-v≡false then check-diversion↦) get↦ =
get-revcat ((p , adaptive f) ∷ bs) bs' check-diversion↦ (get↦ >>= assert-not p-s-v≡false then return refl)
PutGet-with-adaptation :
(bs : List Branch) {s : S} {v : V} {s' : S} (bs' : List Branch) →
{cont : S → Par S} → ({s : S} → cont s ↦ s' → get (revcat bs' bs) s' ↦ v) →
put-with-adaptation bs bs' s v cont ↦ s' → get (revcat bs' bs) s' ↦ v
PutGet-with-adaptation [] bs' PutGet-cont ()
PutGet-with-adaptation ((p , b) ∷ bs) {s} {v} bs' PutGet-cont put↦ with p s v
PutGet-with-adaptation ((p , b) ∷ bs) bs' PutGet-cont put↦ | false =
PutGet-with-adaptation bs ((p , b) ∷ bs') PutGet-cont put↦
PutGet-with-adaptation ((p , normal l q) ∷ bs) bs' PutGet-cont
(put↦ >>= assert p-s'-v≡true then assert q-s'≡true then check-diversion↦ >>= return refl) | true
with get-revcat ((p , normal l q) ∷ bs) bs' check-diversion↦
PutGet-with-adaptation ((p , normal l q) ∷ bs) {s' = s'} bs' PutGet-cont
(put↦ >>= assert p-s'-v≡true then assert q-s'≡true then check-diversion↦ >>= return refl) | true | k rewrite q-s'≡true =
k (Lens.PutGet l put↦ >>= assert p-s'-v≡true then return refl)
PutGet-with-adaptation ((p , adaptive f) ∷ bs) bs' PutGet-cont put↦ | true = PutGet-cont put↦
PutGet : (bs : List Branch) {s s' : S} {v : V} → put bs s v ↦ s' → get bs s' ↦ v
PutGet bs put↦ = PutGet-with-adaptation bs [] (PutGet-with-adaptation bs [] (λ ())) put↦
GetPut-with-adaptation :
(bs : List Branch) {s : S} {v : V} {f : S → Par S}
(bs' : List Branch) → check-diversion bs' s v ↦ tt →
get bs s ↦ v → put-with-adaptation bs bs' s v f ↦ s
GetPut-with-adaptation [] bs' check-diversion↦ ()
GetPut-with-adaptation ((p , b) ∷ bs) {s} {v} bs' check-diversion↦ get↦ with p s v | inspect (p s) v
GetPut-with-adaptation ((p , normal l q) ∷ bs) {s} bs' check-diversion↦ get↦
| false | [ p-s-v≡false ] with q s | inspect q s
GetPut-with-adaptation ((p , normal l q) ∷ bs) bs' check-diversion↦ (get↦ >>= assert-not _ then return refl)
| false | [ p-s-v≡false ] | false | [ q-s≡false ] =
GetPut-with-adaptation bs ((p , normal l q) ∷ bs')
(assert-not p-s-v≡false then assert-not q-s≡false then check-diversion↦) get↦
GetPut-with-adaptation ((p , normal l q) ∷ bs) bs' check-diversion↦ (_ >>= assert p-s-v≡true then return refl)
| false | [ p-s-v≡false ] | true | _ with trans (sym p-s-v≡true) p-s-v≡false
GetPut-with-adaptation ((p , normal l q) ∷ bs) bs' check-diversion↦ (_ >>= assert p-s-v≡true then return refl)
| false | [ p-s-v≡false ] | true | _ | ()
GetPut-with-adaptation ((p , adaptive f) ∷ bs) bs' check-diversion↦ (get↦ >>= assert-not _ then return refl)
| false | [ p-s-v≡false ] =
GetPut-with-adaptation bs ((p , adaptive f) ∷ bs') (assert-not p-s-v≡false then check-diversion↦) get↦
GetPut-with-adaptation ((p , normal l q) ∷ bs) {s} bs' check-diversion↦ get↦
| true | [ p-s-v≡true ] with q s | inspect q s
GetPut-with-adaptation ((p , normal l q) ∷ bs) bs' check-diversion↦ (get↦ >>= assert-not p-s-v≡false then return refl)
| true | [ p-s-v≡true ] | false | [ q-s≡false ] with trans (sym p-s-v≡false) p-s-v≡true
GetPut-with-adaptation ((p , normal l q) ∷ bs) bs' check-diversion↦ (get↦ >>= assert-not p-s-v≡false then return refl)
| true | [ p-s-v≡true ] | false | [ q-s≡false ] | ()
GetPut-with-adaptation ((p , normal l q) ∷ bs) bs' check-diversion↦ (get↦ >>= assert _ then return refl)
| true | [ p-s-v≡true ] | true | [ q-s≡true ] =
Lens.GetPut l get↦ >>= assert p-s-v≡true then assert q-s≡true then check-diversion↦ >>= return refl
GetPut-with-adaptation ((p , adaptive f) ∷ bs) bs' check-diversion↦ (_ >>= assert-not p-s-v≡false then return refl)
| true | [ p-s-v≡true ] with trans (sym p-s-v≡false) p-s-v≡true
GetPut-with-adaptation ((p , adaptive f) ∷ bs) bs' check-diversion↦ (_ >>= assert-not p-s-v≡false then return refl)
| true | [ p-s-v≡true ] | ()
GetPut : (bs : List Branch) {s : S} {v : V} {f : S → Par S} → get bs s ↦ v → put bs s v ↦ s
GetPut bs = GetPut-with-adaptation bs [] (return refl)
case-lens : List Branch → S ⇆ V
case-lens bs = record { put = put bs; get = get bs; PutGet = PutGet bs; GetPut = GetPut bs {f = const fail} }