module Hefty where
open import Function
open import Level using (Level; zero; _⊔_)
open import Data.Sum
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning
open import Data.Universe renaming (Universe to Univ)
private Universe = Univ zero zero
open Univ ⦃ ... ⦄ renaming (U to T; El to ⟦_⟧)
open import Free hiding (_>>=_; _>>_)
open import Free.Nil
variable
m n : Level
F F₀ F₁ F₂ F₃ : Set n → Set (n ⊔ m)
record Effectᴴ : Set₁ where
field Opᴴ : Set
Forkᴴ : Opᴴ → Effect
Retᴴ : Opᴴ → Set
open Effectᴴ public
variable H H′ H″ H‴ H₀ H₁ H₂ H₃ H₄ : Effectᴴ
infixr 12 _∔_
_∔_ : Effectᴴ → Effectᴴ → Effectᴴ
Opᴴ (H₁ ∔ H₂) = Opᴴ H₁ ⊎ Opᴴ H₂
Forkᴴ (H₁ ∔ H₂) = [ Forkᴴ H₁ , Forkᴴ H₂ ]
Retᴴ (H₁ ∔ H₂) = [ Retᴴ H₁ , Retᴴ H₂ ]
data Hefty (H : Effectᴴ) (A : Set) : Set where
pure : A → Hefty H A
impure : (op : Opᴴ H)
(ψ : (s : Op (Forkᴴ H op)) → Hefty H (Ret (Forkᴴ H op) s))
(k : Retᴴ H op → Hefty H A)
→ Hefty H A
record Algᴴ (H : Effectᴴ) (G : Set → Set) : Set₁ where
constructor mkAlg
field alg : (op : Opᴴ H)
(ψ : (s : Op (Forkᴴ H op)) → G (Ret (Forkᴴ H op) s))
(k : Retᴴ H op → G A)
→ G A
open Algᴴ public
cataᴴ : (∀ {A} → A → F A) → Algᴴ H F → Hefty H A → F A
cataᴴ g a (pure x) = g x
cataᴴ g a (impure op ψ k) = alg a op (cataᴴ g a ∘ ψ) (cataᴴ g a ∘ k)
_>>=_ : Hefty H A → (A → Hefty H B) → Hefty H B
pure x >>= g = g x
impure op ψ k >>= g = impure op ψ (λ x → k x >>= g)
_>>_ : Hefty H A → Hefty H B → Hefty H B
m₁ >> m₂ = m₁ >>= λ _ → m₂
fmapᴴ : (A → B) → Hefty H A → Hefty H B
fmapᴴ f (pure x) = pure (f x)
fmapᴴ f (impure op ψ k) = impure op ψ (fmapᴴ f ∘ k)
data _∼_▹_ : Effectᴴ → Effectᴴ → Effectᴴ → Set₁ where
insert : (H₀ ∔ H′) ∼ H₀ ▹ H′
sift : H ∼ H₀ ▹ H′ → (H₁ ∔ H) ∼ H₀ ▹ (H₁ ∔ H′)
instance
insert▹ : (H₀ ∔ H′) ∼ H₀ ▹ H′
insert▹ = insert
sift▹ : ⦃ H ∼ H₀ ▹ H′ ⦄ → (H₁ ∔ H) ∼ H₀ ▹ (H₁ ∔ H′)
sift▹ ⦃ w ⦄ = sift w
inj▹ₗ : ⦃ H ∼ H₀ ▹ H′ ⦄ → Opᴴ H₀ → Opᴴ H
inj▹ₗ ⦃ insert ⦄ = inj₁
inj▹ₗ ⦃ sift p ⦄ = inj₂ ∘ inj▹ₗ ⦃ p ⦄
inj▹ᵣ : ⦃ H ∼ H₀ ▹ H′ ⦄ → Opᴴ H′ → Opᴴ H
inj▹ᵣ ⦃ insert ⦄ = inj₂
inj▹ᵣ ⦃ sift p ⦄ = [ inj₁ , inj₂ ∘ inj▹ᵣ ⦃ p ⦄ ]
inj▹ₗ-ret≡ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ (op : Opᴴ H₀)
→ Retᴴ H (inj▹ₗ op) ≡ Retᴴ H₀ op
inj▹ₗ-ret≡ ⦃ insert ⦄ _ = refl
inj▹ₗ-ret≡ ⦃ sift p ⦄ = inj▹ₗ-ret≡ ⦃ p ⦄
inj▹ᵣ-ret≡ : ⦃ p : H ∼ H₀ ▹ H′ ⦄ (op : Opᴴ H′)
→ Retᴴ H (inj▹ᵣ op) ≡ Retᴴ H′ op
inj▹ᵣ-ret≡ ⦃ insert ⦄ op = refl
inj▹ᵣ-ret≡ ⦃ sift p ⦄ = [ (λ _ → refl) , inj▹ᵣ-ret≡ ⦃ p ⦄ ]
inj▹ₗ-fork≡ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ (op : Opᴴ H₀)
→ Forkᴴ H (inj▹ₗ op) ≡ Forkᴴ H₀ op
inj▹ₗ-fork≡ ⦃ insert ⦄ _ = refl
inj▹ₗ-fork≡ ⦃ sift p ⦄ = inj▹ₗ-fork≡ ⦃ p ⦄
inj▹ᵣ-fork≡ : ⦃ p : H ∼ H₀ ▹ H′ ⦄ (op : Opᴴ H′)
→ Forkᴴ H (inj▹ᵣ op) ≡ Forkᴴ H′ op
inj▹ᵣ-fork≡ ⦃ insert ⦄ op = refl
inj▹ᵣ-fork≡ ⦃ sift p ⦄ = [ (λ _ → refl) , inj▹ᵣ-fork≡ ⦃ p ⦄ ]
inj▹ₗ-prong≡ : ⦃ p : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H₀} (b : Op (Forkᴴ H (inj▹ₗ op)))
→ Ret (Forkᴴ H (inj▹ₗ op)) b ≡ Ret (Forkᴴ H₀ op) (subst Op (inj▹ₗ-fork≡ ⦃ p ⦄ op) b)
inj▹ₗ-prong≡ ⦃ insert ⦄ op = refl
inj▹ₗ-prong≡ ⦃ p = sift p ⦄ {op} b = inj▹ₗ-prong≡ ⦃ p ⦄ b
inj▹ₗ-prong2≡ : ⦃ p : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H₀} (b : Op (Forkᴴ H₀ op))
→ Ret (Forkᴴ H₀ op) b ≡ Ret (Forkᴴ H (inj▹ₗ op)) (subst Op (sym $ inj▹ₗ-fork≡ ⦃ p ⦄ op) b)
inj▹ₗ-prong2≡ ⦃ insert ⦄ op = refl
inj▹ₗ-prong2≡ ⦃ p = sift p ⦄ {op} b = inj▹ₗ-prong2≡ ⦃ p ⦄ b
inj▹ᵣ-prong2≡ : ⦃ p : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H′} (b : Op (Forkᴴ H′ op))
→ Ret (Forkᴴ H′ op) b ≡ Ret (Forkᴴ H (inj▹ᵣ op)) (subst Op (sym $ inj▹ᵣ-fork≡ ⦃ p ⦄ op) b)
inj▹ᵣ-prong2≡ ⦃ insert ⦄ op = refl
inj▹ᵣ-prong2≡ ⦃ p = sift p ⦄ {inj₁ x} b = refl
inj▹ᵣ-prong2≡ ⦃ p = sift p ⦄ {inj₂ x} b = inj▹ᵣ-prong2≡ ⦃ p ⦄ b
inj▹ᵣ-prong≡ : ⦃ p : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H′} (b : Op (Forkᴴ H (inj▹ᵣ op)))
→ Ret (Forkᴴ H (inj▹ᵣ op)) b ≡ Ret (Forkᴴ H′ op) (subst Op (inj▹ᵣ-fork≡ ⦃ p ⦄ op) b)
inj▹ᵣ-prong≡ ⦃ insert ⦄ op = refl
inj▹ᵣ-prong≡ ⦃ p = sift p ⦄ {inj₁ x} b = refl
inj▹ᵣ-prong≡ ⦃ p = sift p ⦄ {inj₂ y} b = inj▹ᵣ-prong≡ ⦃ p ⦄ b
proj-ret▹ₗ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H₀} → Retᴴ H (inj▹ₗ op) → Retᴴ H₀ op
proj-ret▹ₗ ⦃ w = insert ⦄ = id
proj-ret▹ₗ ⦃ w = sift w ⦄ = proj-ret▹ₗ ⦃ w ⦄
proj-ret2▹ₗ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H₀} → Retᴴ H₀ op → Retᴴ H (inj▹ₗ op)
proj-ret2▹ₗ ⦃ w = insert ⦄ = id
proj-ret2▹ₗ ⦃ w = sift w ⦄ = proj-ret2▹ₗ ⦃ w ⦄
proj-ret▹ᵣ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H′} → Retᴴ H (inj▹ᵣ op) → Retᴴ H′ 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 ⦄
proj-ret2▹ᵣ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H′} → Retᴴ H′ op → Retᴴ H (inj▹ᵣ op)
proj-ret2▹ᵣ ⦃ w = insert ⦄ = id
proj-ret2▹ᵣ ⦃ w = sift w ⦄ {op = inj₁ x} = id
proj-ret2▹ᵣ ⦃ w = sift w ⦄ {op = inj₂ y} = proj-ret2▹ᵣ ⦃ w ⦄
proj-fork▹ₗ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H₀}
→ ((b : Op (Forkᴴ H₀ op)) → Hefty H (Ret (Forkᴴ H₀ op) b))
→ ((b : Op (Forkᴴ H (inj▹ₗ op))) → Hefty H (Ret (Forkᴴ H (inj▹ₗ op)) b))
proj-fork▹ₗ ⦃ w ⦄ {op} f b =
let x = f (subst Op (inj▹ₗ-fork≡ ⦃ w ⦄ op) b) in
subst (Hefty _) (sym $ inj▹ₗ-prong≡ ⦃ w ⦄ b) x
proj-fork2▹ₗ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H₀}
→ ((b : Op (Forkᴴ H (inj▹ₗ op))) → Hefty H″ (Ret (Forkᴴ H (inj▹ₗ op)) b))
→ ((b : Op (Forkᴴ H₀ op)) → Hefty H″ (Ret (Forkᴴ H₀ op) b))
proj-fork2▹ₗ ⦃ w ⦄ {op} f b =
let x = f (subst Op (sym $ inj▹ₗ-fork≡ ⦃ w ⦄ op) b) in
subst (Hefty _) (sym $ inj▹ₗ-prong2≡ ⦃ w ⦄ b) x
proj-fork▹ᵣ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H′}
→ ((b : Op (Forkᴴ H′ op)) → Hefty H″ (Ret (Forkᴴ H′ op) b))
→ ((b : Op (Forkᴴ H (inj▹ᵣ op))) → Hefty H″ (Ret (Forkᴴ H (inj▹ᵣ op)) b))
proj-fork▹ᵣ ⦃ w ⦄ {op} f b =
let x = f (subst Op (inj▹ᵣ-fork≡ ⦃ w ⦄ op) b) in
subst (Hefty _) (sym $ inj▹ᵣ-prong≡ ⦃ w ⦄ b) x
proj-fork2▹ᵣ : ⦃ w : H ∼ H₀ ▹ H′ ⦄ {op : Opᴴ H′}
→ ((b : Op (Forkᴴ H (inj▹ᵣ op))) → Hefty H″ (Ret (Forkᴴ H (inj▹ᵣ op)) b))
→ ((b : Op (Forkᴴ H′ op)) → Hefty H″ (Ret (Forkᴴ H′ op) b))
proj-fork2▹ᵣ ⦃ w ⦄ {op} f b =
let x = f (subst Op (sym $ inj▹ᵣ-fork≡ ⦃ w ⦄ op) b) in
subst (Hefty _) (sym $ inj▹ᵣ-prong2≡ ⦃ w ⦄ b) x
case▹ : ⦃ H ∼ H₀ ▹ H′ ⦄
→ Opᴴ H
→ (Opᴴ H₀ → B)
→ (Opᴴ H′ → 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 : H ∼ H₀ ▹ H′ ⦄
→ (op : Opᴴ H)
→ ((op′ : Opᴴ H₀) → op ≡ inj▹ₗ op′ → B)
→ ((op′ : Opᴴ H′) → 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₂)
Elaboration : Effectᴴ → Effect → Set₁
Elaboration H ε = Algᴴ H (Free ε)
infixr 12 _⋎_
_⋎_ : Algᴴ H₁ F → Algᴴ H₂ F → Algᴴ (H₁ ∔ H₂) F
alg (A₁ ⋎ A₂) (inj₁ op) = alg A₁ op
alg (A₁ ⋎ A₂) (inj₂ op) = alg A₂ op
elaborate : Elaboration H Δ → Hefty H A → Free Δ A
elaborate = cataᴴ pure
record Elab (H : Effectᴴ) (Δ : Effect) : Set₁ where
field orate : Algᴴ H (Free Δ)
open Elab public
elab : Elab H Δ → Hefty H A → Free Δ A
elab = elaborate ∘ orate
instance
auto-elab : ⦃ E₁ : Elab H₁ Δ ⦄ ⦃ E₂ : Elab H₂ Δ ⦄ → Elab (H₁ ∔ H₂) Δ
orate (auto-elab ⦃ E₁ ⦄ ⦃ E₂ ⦄) = (orate E₁) ⋎ (orate E₂)