module Free where
open import Level using (Level)
open import Function
open import Data.Unit
open import Data.Sum
open import Relation.Binary.PropositionalEquality hiding ([_])
open ≡-Reasoning
open import Postulate.Extensionality
variable a b : Level
A B C D X Y Z P : Set a
G : Set → Set
record Effect : Set₁ where
field Op : Set
Ret : Op → Set
open Effect public
variable Δ Δ′ Δ″ Δ‴ Δ₀ Δ₁ Δ₂ Δ₃ : Effect
infixr 12 _⊕_
_⊕_ : Effect → Effect → Effect
Op (Δ₁ ⊕ Δ₂) = Op Δ₁ ⊎ Op Δ₂
Ret (Δ₁ ⊕ Δ₂) = [ Ret Δ₁ , Ret Δ₂ ]
data Free (Δ : Effect) (A : Set) : Set where
pure : A → Free Δ A
impure : (op : Op Δ) (k : Ret Δ op → Free Δ A) → Free Δ A
fold : (A → B) → ((op : Op Δ) (k : Ret Δ op → B) → B) → Free Δ A → B
fold gen alg (pure x) = gen x
fold gen alg (impure op k) = alg op (fold gen alg ∘ k)
fmap : (A → B) → Free Δ A → Free Δ B
fmap f = fold (pure ∘ f) impure
_>>=_ : Free Δ A → (A → Free Δ B) → Free Δ B
m >>= g = fold g impure m
_>>_ : Free Δ A → Free Δ B → Free Δ B
m₁ >> m₂ = m₁ >>= λ _ → m₂
fold≡ : (m : Free Δ A) → fold pure impure m ≡ m
fold≡ (pure x) = refl
fold≡ (impure op k) = cong (impure op) (extensionality (λ x → fold≡ (k x)))
Free-unitₗ-≡ : {x : A} (k : A → Free Δ B)
→ pure x >>= k ≡ k x
Free-unitₗ-≡ _ = refl
Free-unitᵣ-≡ : (m : Free Δ A)
→ m >>= pure ≡ m
Free-unitᵣ-≡ (pure x) = refl
Free-unitᵣ-≡ (impure op k) = cong (λ x → impure op x) (extensionality $ λ y → Free-unitᵣ-≡ $ k y)
Free-assoc-≡ : (m : Free Δ A) (k₁ : A → Free Δ B) (k₂ : B → Free Δ C)
→ (m >>= k₁) >>= k₂ ≡ m >>= (λ x → (k₁ x) >>= k₂)
Free-assoc-≡ (pure x) k₁ k₂ = refl
Free-assoc-≡ (impure op k) k₁ k₂ = cong (λ x → impure op x) (extensionality $ λ x → Free-assoc-≡ (k x) k₁ k₂)
Free-cong₂ : (m : Free Δ A) (k k' : A → Free Δ B)
→ (∀ x → k x ≡ k' x)
→ (m >>= k) ≡ (m >>= k')
Free-cong₂ (pure x) k k' eq = eq _
Free-cong₂ (impure op k₁) k k' eq = cong (λ x → impure op x) $ extensionality $ λ x →
cong (λ y → (k₁ x) >>= y) $ extensionality eq
data _∼_▸_ : Effect → Effect → Effect → Set₁ where
insert : (Δ₀ ⊕ Δ′) ∼ Δ₀ ▸ Δ′
sift : (Δ ∼ Δ₀ ▸ Δ′) → ((Δ₁ ⊕ Δ) ∼ Δ₀ ▸ (Δ₁ ⊕ Δ′))
instance
insert▸ : (Δ₀ ⊕ Δ′) ∼ Δ₀ ▸ Δ′
insert▸ = insert
sift▸ : ⦃ Δ ∼ Δ₀ ▸ Δ′ ⦄ → ((Δ₁ ⊕ Δ) ∼ Δ₀ ▸ (Δ₁ ⊕ Δ′))
sift▸ ⦃ w ⦄ = sift w
inj▸ₗ : ⦃ Δ ∼ Δ₀ ▸ Δ′ ⦄ → Op Δ₀ → Op Δ
inj▸ᵣ : ⦃ Δ ∼ Δ₀ ▸ Δ′ ⦄ → Op Δ′ → Op Δ
inj▸ₗ ⦃ insert ⦄ = inj₁
inj▸ₗ ⦃ sift p ⦄ = inj₂ ∘ inj▸ₗ ⦃ p ⦄
inj▸ᵣ ⦃ insert ⦄ = inj₂
inj▸ᵣ ⦃ sift p ⦄ = [ inj₁ , inj₂ ∘ inj▸ᵣ ⦃ p ⦄ ]
proj-ret▸ₗ : ⦃ w : Δ ∼ Δ₀ ▸ Δ′ ⦄ {op : Op Δ₀} → Ret Δ (inj▸ₗ op) → Ret Δ₀ op
proj-ret▸ₗ ⦃ w = insert ⦄ = id
proj-ret▸ₗ ⦃ w = sift w ⦄ = proj-ret▸ₗ ⦃ w ⦄
proj-ret▸ᵣ : ⦃ w : Δ ∼ Δ₀ ▸ Δ′ ⦄ {op : Op Δ′} → Ret Δ (inj▸ᵣ op) → Ret Δ′ op
proj-ret▸ᵣ ⦃ w = insert ⦄ = id
proj-ret▸ᵣ ⦃ w = sift w ⦄ {op = inj₁ x} = id
proj-ret▸ᵣ ⦃ w = sift w ⦄ {op = inj₂ y} = proj-ret▸ᵣ ⦃ w ⦄
inj▸ₗ-ret≡ : ⦃ p : Δ ∼ Δ₀ ▸ Δ′ ⦄ (op : Op Δ₀)
→ Ret Δ (inj▸ₗ op) ≡ Ret Δ₀ op
inj▸ₗ-ret≡ ⦃ insert ⦄ _ = refl
inj▸ₗ-ret≡ ⦃ sift p ⦄ = inj▸ₗ-ret≡ ⦃ p ⦄
inj▸ᵣ-ret≡ : ⦃ p : Δ ∼ Δ₀ ▸ Δ′ ⦄ (op : Op Δ′)
→ Ret Δ (inj▸ᵣ op) ≡ Ret Δ′ op
inj▸ᵣ-ret≡ ⦃ insert ⦄ op = refl
inj▸ᵣ-ret≡ ⦃ sift p ⦄ = [ (λ _ → refl) , inj▸ᵣ-ret≡ ⦃ p ⦄ ]
case▸ : ⦃ Δ ∼ Δ₀ ▸ Δ′ ⦄
→ Op Δ
→ (Op Δ₀ → B)
→ (Op Δ′ → B)
→ B
case▸ ⦃ insert ⦄ x f g = [ f , g ] x
case▸ ⦃ sift p ⦄ x f g = [ g ∘ inj₁ , (λ y → case▸ ⦃ p ⦄ y f (g ∘ inj₂)) ] x
case▸≡ : ⦃ w : Δ ∼ Δ₀ ▸ Δ′ ⦄
→ (op : Op Δ)
→ ((op′ : Op Δ₀) → op ≡ inj▸ₗ op′ → B)
→ ((op′ : Op Δ′) → op ≡ inj▸ᵣ op′ → B)
→ B
case▸≡ ⦃ w = insert ⦄ (inj₁ x) f g = f x refl
case▸≡ ⦃ w = insert ⦄ (inj₂ y) f g = g y refl
case▸≡ ⦃ w = sift p ⦄ (inj₁ x) f g = g (inj₁ x) refl
case▸≡ ⦃ w = sift p ⦄ (inj₂ y) f g = case▸≡ ⦃ p ⦄ y (λ op′ → f op′ ∘ cong inj₂) (λ op′ → g (inj₂ op′) ∘ cong inj₂)
to-front : ⦃ w : Δ ∼ Δ₀ ▸ Δ′ ⦄ → Free Δ A → Free (Δ₀ ⊕ Δ′) A
to-front {Δ₀ = Δ₀} ⦃ w ⦄ (pure x) = pure x
to-front {Δ₀ = Δ₀} ⦃ insert ⦄ (impure op k) = impure op (to-front ⦃ insert ⦄ ∘ k)
to-front {Δ₀ = Δ₀} ⦃ sift w ⦄ (impure (inj₁ op) k) = impure (inj₂ (inj₁ op)) (to-front ⦃ sift w ⦄ ∘ k)
to-front {Δ₀ = Δ₀} ⦃ sift {Δ = Δ} {Δ′ = Δ′} w ⦄ t@(impure (inj₂ op) k) = case▸≡ ⦃ w ⦄ op
(λ op′ eq →
impure
(inj₁ op′)
( to-front ⦃ sift w ⦄
∘ k
∘ subst id (begin
Ret Δ₀ op′
≡⟨ sym (inj▸ₗ-ret≡ ⦃ w ⦄ op′) ⟩
Ret Δ (inj▸ₗ ⦃ w ⦄ op′)
≡⟨ sym $ cong (Ret Δ) eq ⟩
Ret Δ op
∎)))
(λ op′ eq →
impure (inj₂ (inj₂ op′))
( to-front ⦃ sift w ⦄
∘ k
∘ subst id (begin
Ret Δ′ op′
≡⟨ sym (inj▸ᵣ-ret≡ ⦃ w ⦄ op′) ⟩
Ret Δ (inj▸ᵣ ⦃ w ⦄ op′)
≡⟨ (sym $ cong (Ret Δ) eq) ⟩
Ret Δ op
∎)))
from-front : ⦃ w : Δ ∼ Δ₀ ▸ Δ′ ⦄ → Free (Δ₀ ⊕ Δ′) A → Free Δ A
from-front ⦃ w = w ⦄ (pure x) = pure x
from-front ⦃ w = w ⦄ (impure (inj₁ op) k) = impure (inj▸ₗ op) (from-front ∘ k ∘ proj-ret▸ₗ ⦃ w ⦄)
from-front ⦃ w = w ⦄ (impure (inj₂ op) k) = impure (inj▸ᵣ op) (from-front ∘ k ∘ proj-ret▸ᵣ ⦃ w ⦄)
Alg : (Δ : Effect) (A : Set) → Set
Alg Δ A = (op : Op Δ) (k : Ret Δ op → A) → A
record ⟨_!_⇒_⇒_!_⟩ (A : Set) (Δ : Effect) (P : Set) (B : Set) (Δ′ : Effect) : Set₁ where
field ret : A → P → Free Δ′ B
hdl : Alg Δ (P → Free Δ′ B)
open ⟨_!_⇒_⇒_!_⟩ public
given_handle_ : ⦃ Δ ∼ Δ₀ ▸ Δ′ ⦄ → ⟨ A ! Δ₀ ⇒ P ⇒ B ! Δ′ ⟩ → Free Δ A → (P → Free Δ′ B)
given h handle m = fold
(ret h)
[ hdl h , (λ op k p → impure op (λ x → k x p)) ]
(to-front m)
♯_ : ⦃ Δ ∼ Δ₀ ▸ Δ′ ⦄ → Free Δ′ A → Free Δ A
♯_ ⦃ w ⦄ = fold pure (λ op′ k′ → impure (inj▸ᵣ op′) (k′ ∘ proj-ret▸ᵣ ⦃ w ⦄))