{-# OPTIONS --safe #-}
open import Signatures
open import Prelude
module FreeMonad.Syntax.AsSignature (𝔽 : Signature) where
open import FreeMonad.Syntax 𝔽
open Signature 𝔽
Position : Syntax A → Type
Position (var _) = ⊤
Position (op (Oᵢ , k)) = Σ[ i ⦂ Arity Oᵢ ] × Position (k i)
★ : Signature
★ = Syntax ⊤ ◁ Position
open SyntaxBind using (_<$>_; _>>=_)
shape : Syntax A → Syntax ⊤
shape t = const tt <$> t
Index : Syntax A → Type
Index = Position ∘ shape
lookup : (s : Syntax A) → Index s → A
lookup (var x) _ = x
lookup (op (O , k)) (i , is) = lookup (k i) is
fill : (s : Syntax A) → (Position s → B) → Syntax B
fill (var x) i = var (i tt)
fill (op (O , k)) i = op (O , λ j → fill (k j) (i ∘ _,_ j))
⟦op⟧ : ⟦ 𝔽 ⟧ (⟦ ★ ⟧ A) → ⟦ ★ ⟧ A
⟦op⟧ (S , P) = op (S , fst ∘ P) , uncurry (snd ∘′ P)
Indexed : Syntax A ⇔ ⟦ ★ ⟧ A
Indexed .fun s = shape s , lookup s
Indexed .inv = uncurry fill
Indexed .leftInv =
elim-s _ λ { (var x) → refl ; (op (O , k) P⟨xs⟩) → cong (op ∘ _,_ O) (funExt P⟨xs⟩) }
Indexed .rightInv = uncurry (elim-s _ λ { (var x) P → refl ; (op (O , k) P⟨xs⟩) P → cong (⟦op⟧ ∘ _,_ O) (funExt λ i → P⟨xs⟩ i _) })
<$>⇔cmap : (f : A → B) (s : Syntax A) → f <$> s ≡ Indexed .inv (cmap f (Indexed .fun s))
<$>⇔cmap f = elim-s _ λ { (var x) → refl ; (op (O , k) P⟨xs⟩) → cong (op ∘ _,_ O) (funExt P⟨xs⟩) }
<$>-com-inv : (f : A → B) (s : ⟦ ★ ⟧ A) → f <$> Indexed .inv s ≡ Indexed .inv (cmap f s)
<$>-com-inv f s = <$>⇔cmap f (Indexed .inv s) ; cong (Indexed .inv ∘ cmap f) (Indexed .rightInv s)
module _ (f : A → B) (s : Syntax A) where
<$>-com-fun : cmap f (Indexed .fun s) ≡ Indexed .fun (f <$> s)
<$>-com-fun = sym (cong (Indexed .fun) (<$>⇔cmap f s) ; Indexed .rightInv (cmap f (Indexed .fun s)))
<$>-same-shape : shape s ≡ shape (f <$> s)
<$>-same-shape = PathPΣ <$>-com-fun .fst
<$>-lookup : ∀ i → lookup (f <$> s) i ≡ f (lookup s (subst Position (sym <$>-same-shape) i))
<$>-lookup i = sym (cong (_$ i) (fromPathP (PathPΣ <$>-com-fun .snd))) ; transportRefl _
open import Isomorphism.Properties
infixr 5 _∈_ _∉_
_∈_ : A → Syntax A → Type _
x ∈ xs = Fibre (lookup xs) x
_∉_ : A → Syntax A → Type _
x ∉ xs = ¬ (x ∈ xs)
open import Data.Sigma.Properties
module _ (disc : ∀ Oᵢ → Discrete (Signature.Arity 𝔽 Oᵢ)) where
disc-index : (s : Syntax A) → Discrete (Index s)
disc-index =
elim-s _ λ { (var v) _ _ → yes refl
; (op (O , k) P⟨xs⟩) → discreteΣ (disc O) P⟨xs⟩ }
open SyntaxBind
>>=-ind : Syntax A → (A → Syntax B) → Type
>>=-ind xs k = Index (xs >>= k)
>>=∙-ind : Syntax A → (A → Syntax B) → Type
>>=∙-ind xs k = Σ[ i ⦂ Index xs ] × Index (k (lookup xs i))
lookup∙ : (xs : Syntax A) (k : A → Syntax B) → >>=∙-ind xs k → B
lookup∙ xs k = uncurry (lookup ∘′ k ∘′ lookup xs)
module _ (k : A → Syntax B) where
pull-shape : (s : Syntax A) → >>=-ind s k → >>=∙-ind s k
pull-shape = elim-s _ λ { (var x) i → tt , i ; (op (O , k) P⟨xs⟩) (i , is) → let j , js = P⟨xs⟩ i is in (i , j) , js }
push-shape : (s : Syntax A) → >>=∙-ind s k → >>=-ind s k
push-shape = elim-s _ λ { (var x) (i , is) → is ; (op (O , k) P⟨xs⟩) ((i , is) , js) → i , P⟨xs⟩ i (is , js) }
push∘pull : (s : Syntax A) (i : >>=-ind s k) → push-shape s (pull-shape s i) ≡ i
push∘pull = elim-s _ λ { (var x) _ → refl ; (op (O , k) P⟨xs⟩) (i , is) → cong (i ,_) (P⟨xs⟩ i is) }
pull∘push : (s : Syntax A) (i : >>=∙-ind s k) → pull-shape s (push-shape s i) ≡ i
pull∘push =
elim-s _ λ { (var x) _ → refl
; (op (O , k) P⟨xs⟩) ((i , is) , js) p → let (j′ , js′) = P⟨xs⟩ i (is , js) p in ((i , j′) , js′) }
lookup-push : (s : Syntax A) (i : Index s) (is : Index (k (lookup s i))) → lookup (k (lookup s i)) is ≡ lookup (s >>= k) (push-shape s (i , is))
lookup-push = elim-s _ λ { (var x) i is → refl
; (op (O , k) P⟨xs⟩) (i , is′) is → P⟨xs⟩ i is′ is
}
lookup-pull : (s : Syntax A) (i : Index (s >>= k)) → uncurry (lookup ∘′ k ∘′ lookup s) (pull-shape s i) ≡ lookup (s >>= k) i
lookup-pull = elim-s _ λ { (var x) i → refl
; (op (O , k) P⟨xs⟩) (i , is′) → P⟨xs⟩ i is′
}
>>=⟦⟧ : (k : A → Syntax B) (f : ∀ x → Index (k x) → C) (xs : Syntax A)
→ Indexed .inv (shape (xs >>= k) , uncurry (f ∘′ lookup xs) ∘ pull-shape k xs) ≡ xs >>= fill _ ∘′ f
>>=⟦⟧ k f = elim-s _
λ { (var x) → refl ; (op (O , _) P⟨xs⟩) → cong (op ∘ _,_ O) (funExt P⟨xs⟩) }