Final refactor

This commit is contained in:
Leon Vatthauer 2024-02-20 15:09:58 +01:00
parent c2e6966610
commit a3f077bd8d
Signed by: leonv
SSH key fingerprint: SHA256:G4+ddwoZmhLPRB1agvXzZMXIzkVJ36dUYZXf5NxT+u8
22 changed files with 376 additions and 347 deletions

View file

@ -10,6 +10,8 @@ import Categories.Morphism.Reasoning as MR
```
-->
# Guarded and unguarded Elgot algebras
```agda
module Algebra.Elgot {o e} {C : Category o e} (cocartesian : Cocartesian C) where
open Category C
@ -17,8 +19,6 @@ module Algebra.Elgot {o e} {C : Category o e} (cocartesian : Cocartesian
open MR C
```
# Guarded and unguarded Elgot algebras
## Guarded Elgot algebras
Guarded Elgot algebras are algebras on an endofunctor together with an iteration operator that satisfies some axioms.
@ -207,6 +207,7 @@ Here we give a different (easier) Characterization and show that it is equal.
algebra : Elgot-Algebra-on A
open Elgot-Algebra-on algebra public
```
Now we show that unguarded and Id-guarded Elgot algebras are the same.
First we show how to get an Id-guarded algebra from a unguarded one and vice versa:

View file

@ -19,6 +19,8 @@ import Categories.Morphism.Reasoning as MR
```
-->
# Free Elgot algebras
```agda
module Algebra.Elgot.Free {o e} {C : Category o e} (cocartesian : Cocartesian C) where
open import Algebra.Elgot cocartesian
@ -33,11 +35,8 @@ module Algebra.Elgot.Free {o e} {C : Category o e} (cocartesian : Cocart
open M C
```
# Free Elgot algebras
A free elgot algebra is a free object in the category of Elgot algebras.
```agda
elgotForgetfulF : Functor Elgot-Algebras C
elgotForgetfulF = record

View file

@ -16,8 +16,8 @@ open import Categories.Category.BinaryProducts using (BinaryProducts)
import Categories.Morphism as M
import Categories.Morphism.Reasoning as MR
```
In a CCC free elgot algebras are automatically stable.
# In a CCC Free Elgot Algebras are Automatically Stable.
```agda
module Algebra.Elgot.Properties {o e} {C : Category o e} (distributive : Distributive C) (expos : ∀ {A B} → Exponential C A B) where

View file

@ -19,6 +19,8 @@ import Categories.Morphism.Reasoning as MR
```
-->
# Stable Free Elgot Algebras
```agda
module Algebra.Elgot.Stable {o e} {C : Category o e} (distributive : Distributive C) where
open Distributive distributive
@ -38,7 +40,7 @@ module Algebra.Elgot.Stable {o e} {C : Category o e} (distributive : Dis
open M C
```
Stable free Elgot algebras have an additional universal iteration preserving morphism.
Stable free Elgot algebras have an additional universal morphism.
```agda

View file

@ -28,7 +28,8 @@ import Categories.Morphism.Properties as MP'
```
-->
## Summary
# The Ambient Category
We work in an ambient distributive category.
This file contains some helper definitions that will be used throughout the development.

View file

@ -14,7 +14,7 @@ import Categories.Morphism as M
```
-->
# The category of Setoids can be used as instance for ambient category
# The Category of Setoids can be used as the Ambient Category
Most of the required properties are already proven in the agda-categories library, we are only left to show distributivity.

View file

@ -20,6 +20,8 @@ import Categories.Morphism.Properties as MP
```
-->
# Exponentials of Elgot Algebras
```agda
module Category.Construction.ElgotAlgebras.Exponentials {o e} {C : Category o e} (distributive : Distributive C) (exp : ∀ {A B} → Exponential C A B) where
open Category C

View file

@ -14,7 +14,7 @@ import Categories.Morphism.Reasoning as MR
```
-->
# The category of elgot algebras on C is cartesian if C is cartesian
# The Category of Elgot Algebras on C is Cartesian if C is Cartesian
```agda
module Category.Construction.ElgotAlgebras.Products {o e} {C : Category o e} (cocartesian : Cocartesian C) (cartesian : Cartesian C) where

View file

@ -12,7 +12,7 @@ open import Categories.Category.Core
```
-->
# The (functor) category of pre-Elgot monads.
# The (Functor-) Category of Pre-Elgot Monads.
```agda
module Category.Construction.PreElgotMonads {o e} (ambient : Ambient o e) where
@ -23,7 +23,11 @@ open HomReasoning
open Equiv
open M C
open MR C
```
First we define morphisms between pre-Elgot monads:
```agda
module _ (P S : PreElgotMonad) where
private
open PreElgotMonad P using () renaming (T to TP; elgotalgebras to P-elgots)
@ -44,7 +48,11 @@ module _ (P S : PreElgotMonad) where
α-μ : ∀ {X}
α.η X ∘ TP.μ.η X ≈ TS.μ.η X ∘ TS.F.₁ (α.η X) ∘ α.η (TP.F.₀ X)
preserves : ∀ {X A} (f : X ⇒ TP.F.₀ A + X) → α.η A ∘ f #P ≈ ((α.η A +₁ idC) ∘ f) #S
```
Now the category:
```agda
PreElgotMonads : Category (o ⊔ ⊔ e) (o ⊔ ⊔ e) (o ⊔ e)
PreElgotMonads = record
{ Obj = PreElgotMonad

View file

@ -14,7 +14,7 @@ open import Data.Product using (_,_)
```
-->
# The (functor) category of strong pre-Elgot monads.
# The (Functor) Category of Strong Pre-Elgot Monads.
```agda
module Category.Construction.StrongPreElgotMonads {o e} (ambient : Ambient o e) where
@ -25,7 +25,11 @@ open HomReasoning
open Equiv
open M C
open MR C
```
First we look at morphisms between strong pre-Elgot monads:
```agda
module _ (P S : StrongPreElgotMonad) where
private
open StrongPreElgotMonad P using () renaming (SM to SMP; elgotalgebras to P-elgots)
@ -48,7 +52,11 @@ module _ (P S : StrongPreElgotMonad) where
α-strength : ∀ {X Y}
α.η (X × Y) ∘ strengthenP.η (X , Y) ≈ strengthenS.η (X , Y) ∘ (idC ⁂ α.η Y)
α-preserves : ∀ {X A} (f : X ⇒ TP.F.₀ A + X) → α.η A ∘ f #P ≈ ((α.η A +₁ idC) ∘ f) #S
```
Now the category:
```agda
StrongPreElgotMonads : Category (o ⊔ ⊔ e) (o ⊔ ⊔ e) (o ⊔ e)
StrongPreElgotMonads = record
{ Obj = StrongPreElgotMonad

View file

@ -14,6 +14,10 @@ open import Categories.Category.Monoidal.Symmetric using (Symmetric)
```
-->
# Equational Lifting Monads
An equational lifting monad is a commutative monad satisfying one additional equational law
```agda
module Monad.EquationalLifting {o e} {C : Category o e} (cartesian : Cartesian C) where
open Category C

View file

@ -16,23 +16,12 @@ open import Category.Ambient using (Ambient)
open import Data.Product using (∃-syntax; _,_; Σ-syntax)
```
-->
# The Delay Monad
```agda
module Monad.Instance.Delay {o e} (ambient : Ambient o e) where
open Ambient ambient
```
## Definition
The delay monad is usually defined as a coinductive type with two constructors `now : X → D X` and `later : D X → D X`, e.g. in the [agda-stdlib](https://agda.github.io/agda-stdlib/Effect.Monad.Partiality.html#1523)
We will now define it categorically by existence of final coalgebras for the functor `(X + -)` where `X` is some object.
This functor trivially sends objects `Y` to `X + Y` and functions `f` to `id + f`.
In this definition `D X` is the underlying object of the final coalgebra given by `X`.
We then use Lambek's Lemma to gain an isomorphism `D X ≅ X + D X`, whose inverse can be factored into the constructors `now` and `later`.
<!--
```agda
open M C
open MR C
open Equiv
@ -41,7 +30,14 @@ We then use Lambek's Lemma to gain an isomorphism `D X ≅ X + D X`, whose inver
open F-Coalgebra-Morphism renaming (f to u)
open F-Coalgebra
```
-->
The delay monad is usually defined as a coinductive type with two constructors `now : X → D X` and `later : D X → D X`, e.g. in the [agda-stdlib](https://agda.github.io/agda-stdlib/Effect.Monad.Partiality.html#1523)
We will now define it categorically by existence of final coalgebras for the functor `(X + -)` where `X` is some object.
This functor trivially sends objects `Y` to `X + Y` and functions `f` to `id + f`.
In this definition `D X` is the underlying object of the final coalgebra given by `X`.
We then use Lambek's Lemma to gain an isomorphism `D X ≅ X + D X`, whose inverse can be factored into the constructors `now` and `later`.
```agda
record DelayM : Set (o ⊔ ⊔ e) where
@ -78,8 +74,6 @@ We then use Lambek's Lemma to gain an isomorphism `D X ≅ X + D X`, whose inver
D₀ X = DX {X}
```
## Delay is a monad
The next step is showing that this actually yields a monad. Some parts for this are already given, we can construct `D X` from `X` and `now : D X ⇒ D X` is the monad unit.
What's missing is Kleisli-lifting, given a morphism `f : X ⇒ D Y` we need to construct a morphism `extend f : D X ⇒ D Y`.
To do so we go from `D X` to `D X + D Y` via injection and then construct a coalgebra `D X + D Y ⇒ Y + (D X + D Y)`, the final coalgebra `D Y ⇒ Y + D Y` then yields a coalgebra-morphism from `D X + D Y` to `D Y`, see the following diagram:

View file

@ -17,6 +17,8 @@ open import Categories.NaturalTransformation
```
-->
# The Delay Monad is Commutative
```agda
module Monad.Instance.Delay.Commutative {o e} (ambient : Ambient o e) (D : DelayM ambient) where
open Ambient ambient
@ -36,8 +38,6 @@ module Monad.Instance.Delay.Commutative {o e} (ambient : Ambient o e) (D
open NaturalTransformation (StrongMonad.strengthen strongMonad) using () renaming (commute to τ-commute)
```
# The Delay Monad is commutative
```agda
commutativeMonad : Commutative braided strongMonad
commutativeMonad = record { commutes = λ {X} {Y} → pullˡ (Kleisli⇒Monad⇒Kleisli kleisli _) ○ commutes' ○ pushˡ (sym (Kleisli⇒Monad⇒Kleisli kleisli _)) }

View file

@ -18,7 +18,7 @@ open import Categories.Category.Product renaming (Product to CProduct; _⁂_ to
```
-->
# The Delay Monad is a Strong Monad
# The Delay Monad is Strong
```agda
module Monad.Instance.Delay.Strong {o e} (ambient : Ambient o e) (D : DelayM ambient) where

View file

@ -14,7 +14,7 @@ open import Categories.Category.BinaryProducts using (BinaryProducts)
```
-->
# The monad K
# The Monad K
```agda
module Monad.Instance.K {o e} (ambient : Ambient o e) where
@ -33,7 +33,6 @@ module Monad.Instance.K {o e} (ambient : Ambient o e) where
open HomReasoning
```
## Definition
Existence of stable free Elgot algebras yields the monad K
```agda

View file

@ -11,7 +11,7 @@ open import Categories.Morphism.Properties
```
-->
# **K** is a Commutative Monad
# K is a Commutative Monad
```agda
module Monad.Instance.K.Commutative {o e} (ambient : Ambient o e) (MK : MIK.MonadK ambient) where

View file

@ -12,7 +12,7 @@ open import Categories.Morphism.Properties
```
-->
# **K** is an equational lifting monad
# K is an equational lifting monad
```agda
module Monad.Instance.K.EquationalLifting {o e} (ambient : Ambient o e) (MK : MIK.MonadK ambient) where

View file

@ -19,7 +19,7 @@ import Monad.Instance.K as MIK
```
-->
# **K** is a Strong Monad
# K is a Strong Monad
```agda
module Monad.Instance.K.Strong {o e} (ambient : Ambient o e) (MK : MIK.MonadK ambient) where

View file

@ -16,6 +16,8 @@ import Monad.Instance.K as MIK
```
-->
# K is the Initial Strong Pre-Elgot Monad
```agda
module Monad.Instance.K.StrongPreElgot {o e} (ambient : Ambient o e) (MK : MIK.MonadK ambient) where
open Ambient ambient
@ -39,8 +41,6 @@ open MR C
open M C
```
# K is the Initial Strong Pre-Elgot Monad
We have already shown that **K** is strong and it is pre-Elgot by definition, so it follows:
```agda

View file

@ -44,7 +44,7 @@ module _ (A : Set c) where
later : Delay → Delay
record Delay : Set c where
coinductive
constructor delay
constructor dela
field force : Delay
open Delay public
@ -168,15 +168,14 @@ module DelayMonad where
μ : ∀ {A : Setoid c (c ⊔ )} → Delay (Delay A ) → Delay A
μ {A} (now x) = x
μ {A} (later x) = later λ { .force → μ {A} (force x) }
open DelayMonad public
open DelayMonad
```
Some helpers for reasoning with setoid morphisms:
```agda
open Bisimilarity renaming (_≈_ to [_][_≈_]; _≈_ to [_][_≈_]; __ to [_][__]; __ to [_][__]; _↓_ to [_][_↓_]; _≲_ to [_][_≲_]; _≲_ to [_][_≲_])
private <_> = _⟨$⟩_
open _⟶_ using (cong)
open _⟶_ using (cong) renaming (to to <_>)
-- pointwise equality between setoid morphisms:
_≐_ : ∀ {c' '} {A B : Setoid c' '} → A ⟶ B → A ⟶ B → Set (c' ⊔ ')
_≐_ {c'} {'} {A} {B} f g = Setoid._≈_ (A ⇨ B) f g

View file

@ -19,20 +19,17 @@ open import Data.Product.Relation.Binary.Pointwise.NonDependent
open import Data.Product
open import Category.Ambient using (Ambient)
open import Categories.Category.CartesianClosed
open import Categories.Monad
open import Categories.Category.Instance.Setoids
open import Categories.Category.Instance.Properties.Setoids.CCC using (Setoids-CCC)
```
-->
# The delay monad on the category of setoids is an instance of K
TODO use new names defined in Delay.algda.md open the monad modules i.e.
open Monad delayMonad renaming (...)
open Monad delayMonad≈ renaming (...)
# The Delay Monad Quotiented by Weak Bisimilarity is an Instance of K on the Category of Setoids
```agda
module Monad.Instance.Setoids.K { : Level} where
open _⟶_ using (cong)
open _⟶_ using (cong) renaming (to to <_>)
open import Category.Ambient.Setoids
open Ambient (setoidAmbient {} {}) using (cocartesian; distributive)
open import Monad.Instance.Setoids.Delay {} {}
@ -48,357 +45,366 @@ module Monad.Instance.Setoids.K { : Level} where
open nat
open Setoid using () renaming (Carrier to _; _≈_ to [_][_≡_])
open eq using () renaming (refl to ≡-refl; sym to ≡-sym; trans to ≡-trans)
open DelayMonad
open DelayMonad
open DelayMonad≈
open Monad delayMonad using () renaming (F to Delay; η to η∼; μ to μ∼; assoc to assoc; sym-assoc to sym-assoc; identityˡ to identityˡ; identityʳ to identityʳ)
open Monad delayMonad≈ using () renaming (F to Delay≈; η to η≈; μ to μ≈; assoc to assoc≈; sym-assoc to sym-assoc≈; identityˡ to identityˡ≈; identityʳ to identityʳ≈)
```
≡→≡ : ∀ {A : Setoid } {x y : A } → x ≡ y → [ A ][ x ≡ y ]
≡→≡ {A} {x} {y} eq rewrite eq = ≡-refl A
Let us first show that every Delay≈ X admits an Elgot algebra structure.
iter : ∀ {A X : Setoid } → ( X → (Delay A X )) → X → Delay A
iter : ∀ {A X : Setoid } → ( X → (Delay A X )) → X → Delay A
force (iter {A} {X} f x) = iter {A} {X} f x
iter {A} {X} f x with f x
... | inj₁ a = a
... | inj₂ b = later (iter {A} {X} f b)
We start by defining the iteration operator:
conflict : ∀ {''} (X Y : Setoid ) {Z : Set ''}
{x : X } {y : Y } → [ X ⊎ₛ Y ][ inj₁ x ≡ inj₂ y ] → Z
conflict X Y ()
```agda
private
iter : ∀ {A X : Setoid } → ( X → (Delay A X )) → X → Delay A
iter {A} {X} f x with f x
... | inj₁ a = a
... | inj₂ b = later λ { .force → iter {A} {X} f b }
```
inj₁-helper : ∀ {X Y : Setoid } (f : X ⟶ (Y ⊎ₛ X)) {x y : X } {a b : Y } → [ X ][ x ≡ y ] → f ⟨$⟩ x ≡ inj₁ a → f ⟨$⟩ y ≡ inj₁ b → [ Y ][ a ≡ b ]
inj₁-helper {X} {Y} f {x} {y} {a} {b} x≡y fi₁ fi₂ = drop-inj₁ {x = a} {y = b} helper
where
Some helper lemmas for reasoning about coproducts
```agda
conflict : ∀ {''} (X Y : Setoid ) {Z : Set ''}
{x : X } {y : Y } → [ X ⊎ₛ Y ][ inj₁ x ≡ inj₂ y ] → Z
conflict X Y ()
inj₁-helper : ∀ {X Y : Setoid } (f : X ⟶ (Y ⊎ₛ X)) {x y : X } {a b : Y } → [ X ][ x ≡ y ] → f ⟨$⟩ x ≡ inj₁ a → f ⟨$⟩ y ≡ inj₁ b → [ Y ][ a ≡ b ]
inj₁-helper {X} {Y} f {x} {y} {a} {b} x≡y fi₁ fi₂ = drop-inj₁ {x = a} {y = b} helper
where
helper : [ Y ⊎ₛ X ][ inj₁ a ≡ inj₁ b ]
helper rewrite (≣-sym fi₁) | (≣-sym fi₂) = cong f x≡y
inj₂-helper : ∀ {X Y : Setoid } (f : X ⟶ (Y ⊎ₛ X)) {x y : X } {a b : X } → [ X ][ x ≡ y ] → f ⟨$⟩ x ≡ inj₂ a → f ⟨$⟩ y ≡ inj₂ b → [ X ][ a ≡ b ]
inj₂-helper {X} {Y} f {x} {y} {a} {b} x≡y fi₁ fi₂ = drop-inj₂ {x = a} {y = b} helper
where
inj₂-helper : ∀ {X Y : Setoid } (f : X ⟶ (Y ⊎ₛ X)) {x y : X } {a b : X } → [ X ][ x ≡ y ] → f ⟨$⟩ x ≡ inj₂ a → f ⟨$⟩ y ≡ inj₂ b → [ X ][ a ≡ b ]
inj₂-helper {X} {Y} f {x} {y} {a} {b} x≡y fi₁ fi₂ = drop-inj₂ {x = a} {y = b} helper
where
helper : [ Y ⊎ₛ X ][ inj₂ a ≡ inj₂ b ]
helper rewrite (≣-sym fi₁) | (≣-sym fi₂) = cong f x≡y
absurd-helper : ∀ {'} {X Y : Setoid } {A : Set '} (f : X ⟶ (Y ⊎ₛ X)) {x y : X } {a : Y } {b : X } → [ X ][ x ≡ y ] → f ⟨$⟩ x ≡ inj₁ a → f ⟨$⟩ y ≡ inj₂ b → A
absurd-helper {'} {X} {Y} {A} f {x} {y} {a} {b} x≡y fi₁ fi₂ = conflict Y X helper
where
absurd-helper : ∀ {'} {X Y : Setoid } {A : Set '} (f : X ⟶ (Y ⊎ₛ X)) {x y : X } {a : Y } {b : X } → [ X ][ x ≡ y ] → f ⟨$⟩ x ≡ inj₁ a → f ⟨$⟩ y ≡ inj₂ b → A
absurd-helper {'} {X} {Y} {A} f {x} {y} {a} {b} x≡y fi₁ fi₂ = conflict Y X helper
where
helper : [ Y ⊎ₛ X ][ inj₁ a ≡ inj₂ b ]
helper rewrite (≣-sym fi₁) | (≣-sym fi₂) = cong f x≡y
```
iter-cong : ∀ {A X : Setoid } (f : X ⟶ (Delay A ⊎ₛ X)) {x y : X } → [ X ][ x ≡ y ] → [ A ][ (iter {A} {X} < f > x) (iter {A} {X} < f > y) ]
iter-cong : ∀ {A X : Setoid } (f : X ⟶ (Delay A ⊎ₛ X)) {x y : X } → [ X ][ x ≡ y ] → [ A ][ (iter {A} {X} < f > x) (iter {A} {X} < f > y) ]
force (iter-cong {A} {X} f {x} {y} x≡y) = iter-cong f x≡y
iter-cong {A} {X} f {x} {y} x≡y with < f > x in eqx | < f > y in eqy
... | inj₁ a | inj₁ b = inj₁-helper f x≡y eqx eqy
... | inj₁ a | inj₂ b = absurd-helper f x≡y eqx eqy
... | inj₂ a | inj₁ b = absurd-helper f (≡-sym X x≡y) eqy eqx
... | inj₂ a | inj₂ b = later (iter-cong {A} {X} f (inj₂-helper f x≡y eqx eqy))
Now we show that `iter` defines an Elgot algebra structure on `Delay≈`
iter-cong : ∀ {A X : Setoid } (f : X ⟶ (Delay≈ A ⊎ₛ X)) {x y : X } → [ X ][ x ≡ y ] → [ A ][ (iter {A} {X} < f > x) ≈ (iter {A} {X} < f > y) ]
iter-cong : ∀ {A X : Setoid } (f : X ⟶ (Delay≈ A ⊎ₛ X)) {x y : X } → [ X ][ x ≡ y ] → [ A ][ (iter {A} {X} < f > x) ≈′ (iter {A} {X} < f > y) ]
force≈ (iter-cong {A} {X} f {x} {y} x≡y) = iter-cong f x≡y
iter-cong {A} {X} f {x} {y} x≡y with < f > x in eqx | < f > y in eqy
... | inj₁ a | inj₁ b = inj₁-helper f x≡y eqx eqy
... | inj₁ a | inj₂ b = absurd-helper f x≡y eqx eqy
... | inj₂ a | inj₁ b = absurd-helper f (≡-sym X x≡y) eqy eqx
... | inj₂ a | inj₂ b = later≈ (iter-cong {A} {X} f (inj₂-helper f x≡y eqx eqy))
```
-- iter is a congruence wrt to strong bisimilarity
iter : ∀ {A X : Setoid } → (X ⟶ (Delay.₀ A ⊎ₛ X)) → X ⟶ Delay.₀ A
< iter {A} {X} f > = iter {A} {X} < f >
cong (iter {A} {X} f) {x} {y} x≡y with < f > x in eqx | < f > y in eqy
... | inj₁ a | inj₁ b = inj₁-helper f x≡y eqx eqy
... | inj₁ a | inj₂ b = absurd-helper f x≡y eqx eqy
... | inj₂ a | inj₁ b = absurd-helper f (≡-sym X x≡y) eqy eqx
... | inj₂ a | inj₂ b = later λ { .force → cong (iter {A} {X} f) (inj₂-helper f x≡y eqx eqy) }
iterₛ : ∀ {A X : Setoid } → (X ⟶ (Delay A ⊎ₛ X)) → X ⟶ Delay A
iterₛ {A} {X} f = record { to = iter {A} {X} < f > ; cong = iter-cong {A} {X} f }
-- iter is a congruence wrt to weak bisimilarity
iter≈ : ∀ {A X : Setoid } → (X ⟶ (Delay≈.₀ A ⊎ₛ X)) → X ⟶ Delay≈.₀ A
< iter {A} {X} f > = iter {A} {X} < f >
cong (iter≈ {A} {X} f) {x} {y} x≡y with < f > x in eqx | < f > y in eqy
... | inj₁ a | inj₁ b = inj₁-helper f x≡y eqx eqy
... | inj₁ a | inj₂ b = absurd-helper f x≡y eqx eqy
... | inj₂ a | inj₁ b = absurd-helper f (≡-sym X x≡y) eqy eqx
... | inj₂ a | inj₂ b = later≈ λ { .force≈ → cong (iter≈ {A} {X} f) (inj₂-helper f x≡y eqx eqy) }
iterₛ : ∀ {A X : Setoid } → (X ⟶ (Delay≈ A ⊎ₛ X)) → X ⟶ Delay≈ A
iterₛ {A} {X} f = record { to = iter {A} {X} < f > ; cong = iter-cong {A} {X} f }
-- iter satisfies the fixpoint law
iter≈-fixpoint : ∀ {A X : Setoid } {f : X ⟶ (Delay≈.₀ A ⊎ₛ X)} {x : X } → [ A ][ iter {A} {X} < f > x ≈ [ Function.id , iter {A} {X} < f > ] (f ⟨$⟩ x) ]
iter≈-fixpoint {A} {X} {f} {x} with < f > x in eqx
... | inj₁ a = ≈-refl A
... | inj₂ a = ≈-trans A (≈-sym A later-self) (≈-refl A)
iter-fixpoint : ∀ {A X : Setoid } {f : X ⟶ (Delay≈ A ⊎ₛ X)} {x : X } → [ A ][ iter {A} {X} < f > x ≈ [ Function.id , iter {A} {X} < f > ] (f ⟨$⟩ x) ]
iter-fixpoint {A} {X} {f} {x} with < f > x in eqx
... | inj₁ a = ≈-refl A
... | inj₂ a = ≈-trans A (≈-sym A later-self) (≈-refl A)
iter-resp-≈ : ∀ {A X : Setoid } (f g : X ⟶ (Delay≈ A ⊎ₛ X)) → f ≐ g → ∀ {x y : X } → [ X ][ x ≡ y ] → [ A ][ iter {A} {X} < f > x ≈ iter {A} {X} < g > y ]
iter-resp-≈′ : ∀ {A X : Setoid } (f g : X ⟶ (Delay≈ A ⊎ₛ X)) → f ≐ g → ∀ {x y : X } → [ X ][ x ≡ y ] → [ A ][ iter {A} {X} < f > x ≈′ iter {A} {X} < g > y ]
force≈ (iter-resp-≈′ {A} {X} f g f≐g {x} {y} x≡y) = iter-resp-≈ f g f≐g {x} {y} x≡y
iter-resp-≈ {A} {X} f g f≐g {x} {y} x≡y with < f > x in eqa | < g > y in eqb
... | inj₁ a | inj₁ b = drop-inj₁ helper
where
helper : [ Delay≈ A ⊎ₛ X ][ inj₁ a ≡ inj₁ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈ A ⊎ₛ X) (cong f x≡y) f≐g
... | inj₁ a | inj₂ b = conflict (Delay≈ A) X helper
where
helper : [ Delay≈ A ⊎ₛ X ][ inj₁ a ≡ inj₂ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈ A ⊎ₛ X) (cong f x≡y) f≐g
... | inj₂ a | inj₁ b = conflict (Delay≈ A) X (≡-sym (Delay≈ A ⊎ₛ X) helper)
where
helper : [ Delay≈ A ⊎ₛ X ][ inj₂ a ≡ inj₁ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈ A ⊎ₛ X) (cong f x≡y) f≐g
... | inj₂ a | inj₂ b = later≈ (iter-resp-≈′ f g f≐g (drop-inj₂ helper))
where
helper : [ Delay≈ A ⊎ₛ X ][ inj₂ a ≡ inj₂ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈ A ⊎ₛ X) (cong f x≡y) f≐g
iter-uni : ∀ {A X Y : Setoid } {f : X ⟶ (Delay≈ A ⊎ₛ X)} {g : Y ⟶ (Delay≈ A ⊎ₛ Y)} {h : X ⟶ Y}
→ ([ inj₁ₛ , inj₂ₛ ∘ h ]ₛ ∘ f) ≐ (g ∘ h)
→ ∀ {x : X } {y : Y } → [ Y ][ y ≡ h ⟨$⟩ x ] → [ A ][ iter {A} {X} < f > x ≈ (iter {A} {Y} < g >) y ]
iter-uni : ∀ {A X Y : Setoid } {f : X ⟶ (Delay≈ A ⊎ₛ X)} {g : Y ⟶ (Delay≈ A ⊎ₛ Y)} {h : X ⟶ Y}
→ ([ inj₁ₛ , inj₂ₛ ∘ h ]ₛ ∘ f) ≐ (g ∘ h)
→ ∀ {x : X } {y : Y } → [ Y ][ y ≡ h ⟨$⟩ x ] → [ A ][ iter {A} {X} < f > x ≈′ (iter {A} {Y} < g >) y ]
force≈ (iter-uni {A} {X} {Y} {f} {g} {h} eq {x} {y} y≡h$x) = iter-uni {A} {X} {Y} {f} {g} {h} eq {x} {y} y≡h$x
iter-uni {A} {X} {Y} {f} {g} {h} eq {x} {y} x≡y with f ⟨$⟩ x in eqx | g ⟨$⟩ (h ⟨$⟩ x) in eqy | g ⟨$⟩ y in eqz | eq {x}
... | inj₁ a | inj₁ b | inj₁ c | inj₁ a≈c = ≈-trans A a≈c (inj₁-helper g (≡-sym Y x≡y) eqy eqz)
... | inj₁ a | inj₁ b | inj₂ c | inj₁ _ = absurd-helper g (≡-sym Y x≡y) eqy eqz
... | inj₂ a | inj₂ b | inj₁ c | inj₂ _ = absurd-helper g x≡y eqz eqy
... | inj₂ a | inj₂ b | inj₂ c | inj₂ req = later≈ (iter-uni {f = f} {g = g}{h = h} eq c≡h$a)
where
-- iter satisfies the uniformity law
iter-uni : ∀ {A X Y : Setoid } {f : X ⟶ (Delay≈.₀ A ⊎ₛ X)} {g : Y ⟶ (Delay≈.₀ A ⊎ₛ Y)} {h : X ⟶ Y}
→ ([ inj₁ₛ , inj₂ₛ ∘ h ]ₛ ∘ f) ≐ (g ∘ h)
→ ∀ {x : X } {y : Y } → [ Y ][ y ≡ h ⟨$⟩ x ] → [ A ][ iter {A} {X} < f > x ≈ (iter {A} {Y} < g >) y ]
iter-uni {A} {X} {Y} {f} {g} {h} eq {x} {y} x≡y with f ⟨$⟩ x in eqx | g ⟨$⟩ (h ⟨$⟩ x) in eqy | g ⟨$⟩ y in eqz | eq {x}
... | inj₁ a | inj₁ b | inj₁ c | inj₁ a≈c = ≈-trans A a≈c (inj₁-helper g (≡-sym Y x≡y) eqy eqz)
... | inj₁ a | inj₁ b | inj₂ c | inj₁ _ = absurd-helper g (≡-sym Y x≡y) eqy eqz
... | inj₂ a | inj₂ b | inj₁ c | inj₂ _ = absurd-helper g x≡y eqz eqy
... | inj₂ a | inj₂ b | inj₂ c | inj₂ req = later≈ λ { .force≈ → iter-uni {A} {X} {Y} {f} {g} {h} eq c≡h$a }
where
c≡h$a : [ Y ][ c ≡ h ⟨$⟩ a ]
c≡h$a = ≡-trans Y (drop-inj₂ (≡-trans (Delay≈ A ⊎ₛ Y) (≡-trans (Delay≈ A ⊎ₛ Y) (≡-sym (Delay≈ A ⊎ₛ Y) (≡→≡ {Delay≈ A ⊎ₛ Y} eqz)) (cong g x≡y)) (≡→≡ {Delay≈ A ⊎ₛ Y} eqy))) (≡-sym Y req)
c≡h$a = ≡-trans Y (drop-inj₂ (≡-trans (Delay≈.₀ A ⊎ₛ Y) (≡-trans (Delay≈.₀ A ⊎ₛ Y) (≡-sym (Delay≈.₀ A ⊎ₛ Y) (≡→≡ {Delay≈.₀ A ⊎ₛ Y} eqz)) (cong g x≡y)) (≡→≡ {Delay≈.₀ A ⊎ₛ Y} eqy))) (≡-sym Y req)
where
≡→≡ : ∀ {A : Setoid } {x y : A } → x ≡ y → [ A ][ x ≡ y ]
≡→≡ {A} {x} {y} eq rewrite eq = ≡-refl A
iter-folding : ∀ {A X Y : Setoid } {f : X ⟶ (Delay≈ A ⊎ₛ X)} {h : Y ⟶ (X ⊎ₛ Y)} {x : X ⊎ₛ Y } → [ A ][ iter {A} {X ⊎ₛ Y} [ inj₁ ∘f iter {A} {X} < f > , inj₂ ∘f < h > ] x ≈ iter {A} {X ⊎ₛ Y} [ [ inj₁ , inj₂ ∘′ inj₁ ] ∘f < f > , (inj₂ ∘f < h >) ] x ]
iter-folding : ∀ {A X Y : Setoid } {f : X ⟶ (Delay≈ A ⊎ₛ X)} {h : Y ⟶ (X ⊎ₛ Y)} {x : X ⊎ₛ Y } → [ A ][ iter {A} {X ⊎ₛ Y} [ inj₁ ∘f iter {A} {X} < f > , inj₂ ∘f < h > ] x ≈′ iter {A} {X ⊎ₛ Y} [ [ inj₁ , inj₂ ∘′ inj₁ ] ∘f < f > , (inj₂ ∘f < h >) ] x ]
force≈ (iter-folding {A} {X} {Y} {f} {h} {x}) = iter-folding {A} {X} {Y} {f} {h} {x}
iter-folding {A} {X} {Y} {f} {h} {inj₁ x} with f ⟨$⟩ x in eqa
... | inj₁ a = ≈-refl A
... | inj₂ a = later≈ (helper a)
where
-- iter satisfies the folding law
iter-folding : ∀ {A X Y : Setoid } {f : X ⟶ (Delay≈.₀ A ⊎ₛ X)} {h : Y ⟶ (X ⊎ₛ Y)} {x : X ⊎ₛ Y } → [ A ][ iter {A} {X ⊎ₛ Y} [ inj₁ ∘f iter {A} {X} < f > , inj₂ ∘f < h > ] x ≈ iter {A} {X ⊎ₛ Y} [ [ inj₁ , inj₂ ∘′ inj₁ ] ∘f < f > , (inj₂ ∘f < h >) ] x ]
iter-folding {A} {X} {Y} {f} {h} {inj₂ x} with h ⟨$⟩ x in eqa
... | inj₁ a = later≈ λ { .force≈ → iter-folding {A} {X} {Y} {f} {h} {inj₁ a} }
... | inj₂ a = later≈ λ { .force≈ → iter-folding {A} {X} {Y} {f} {h} {inj₂ a} }
iter-folding {A} {X} {Y} {f} {h} {inj₁ x} with f ⟨$⟩ x in eqa
... | inj₁ a = ≈-refl A
... | inj₂ a = later≈ λ { .force≈ → helper a }
where
helper : ∀ (b : X ) → [ A ][ iter < f > b ≈ iter [ [ inj₁ , inj₂ ∘′ inj₁ ] ∘′ < f > , inj₂ ∘′ < h > ] (inj₁ b) ]
helper : ∀ (b : X ) → [ A ][ iter < f > b ≈′ iter [ [ inj₁ , inj₂ ∘′ inj₁ ] ∘′ < f > , inj₂ ∘′ < h > ] (inj₁ b) ]
helper b with f ⟨$⟩ b in eqb
... | inj₁ c = ≈-refl A
... | inj₂ c = later≈ (helper c)
force≈ (helper b) = helper b
iter-folding {A} {X} {Y} {f} {h} {inj₂ x} with h ⟨$⟩ x in eqa
... | inj₁ a = later≈ (iter-folding {A} {X} {Y} {f} {h} {inj₁ a})
... | inj₂ a = later≈ (iter-folding {A} {X} {Y} {f} {h} {inj₂ a})
... | inj₂ c = later≈ λ { .force≈ → helper c }
delay-algebras-on : ∀ {A : Setoid } → Elgot-Algebra-on (Delay≈ A)
delay-algebras-on {A} = record
{ _# = iterₛ {A}
; #-Fixpoint = λ {X} {f} → iter-fixpoint {A} {X} {f}
; #-Uniformity = λ {X} {Y} {f} {g} {h} eq {x} → iter-uni {A} {X} {Y} {f} {g} {h} eq {x} {h ⟨$⟩ x} (≡-refl Y)
; #-Folding = λ {X} {Y} {f} {h} {x} → iter-folding {A} {X} {Y} {f} {h} {x}
; #-resp-≈ = λ {X} {f} {g} f≐g {x} → iter-resp-≈ {A} {X} f g f≐g {x} {x} (≡-refl X)
}
delay-algebras : ∀ (A : Setoid ) → Elgot-Algebra
delay-algebras A = record { A = Delay≈ A ; algebra = delay-algebras-on {A}}
open Elgot-Algebra using (#-Fixpoint; #-Uniformity; #-Compositionality; #-resp-≈; #-Diamond) renaming (A to ⟦_⟧)
delay-lift : ∀ {A : Setoid } {B : Elgot-Algebra} → A ⟶ ⟦ B ⟧ → Elgot-Algebra-Morphism (delay-algebras A) B
delay-lift {A} {B} f = record { h = delay-lift' ; preserves = λ {X} {g} {x} → preserves' {X} {g} {x} }
where
open Elgot-Algebra B using (_#)
-- (f + id) ∘ out
helper₁ : Delay A ⟦ B ⟧ ⊎ Delay A
helper₁ (now x) = inj₁ (< f > x)
helper₁ (later x) = inj₂ (force x)
helper₁-cong : {x y : Delay A } → (xy : [ A ][ x y ]) → [ ⟦ B ⟧ ⊎ₛ Delay A ][ helper₁ x ≡ helper₁ y ]
helper₁-cong (now x≡y) = inj₁ (cong f x≡y)
helper₁-cong (later x≡y) = inj₂ (force x≡y)
-- -- setoid-morphism that preserves strong-bisimilarity
helper : (Delay A) ⟶ (⟦ B ⟧ ⊎ₛ Delay A)
helper = record { to = helper₁ ; cong = helper₁-cong}
helper#-cong : {x y : Delay A } → (xy : [ A ][ x y ]) → [ ⟦ B ⟧ ][ helper # ⟨$⟩ x ≡ helper # ⟨$⟩ y ]
helper#-cong {x} {y} xy = cong (helper #) xy
helper#≈-cong : {x y : Delay A } → (x≈y : [ A ][ x ≈ y ]) → [ ⟦ B ⟧ ][ helper # ⟨$⟩ x ≡ helper # ⟨$⟩ y ]
-- key special case
helper#≈-cong' : {z : Delay ( A × )} → [ ⟦ B ⟧ ][ helper # ⟨$⟩ liftF proj₁ z ≡ helper # ⟨$⟩ μ {A} (liftF (ι {A}) z) ]
helper#≈-cong x≈y =
≡-trans ⟦ B ⟧
(helper#-cong (-sym A (delta-prop₂ {A} ineq₂)))
(≡-trans ⟦ B ⟧
(≡-trans ⟦ B ⟧
(≡-sym ⟦ B ⟧ (helper#≈-cong' {z₂})) (≡-trans ⟦ B ⟧ (helper#-cong (-trans A (delta-prop₁ (≈→≲ (≈-sym A x≈y))) (-sym A (-trans A (delta-prop₁ (≈→≲ x≈y)) (race-sym≈ x≈y))))) (helper#≈-cong' {z₁})))
(helper#-cong (delta-prop₂ {A} ineq₁)))
-- iter respects pointwise equality
iter≈-resp-≐ : ∀ {A X : Setoid } (f g : X ⟶ (Delay≈.₀ A ⊎ₛ X)) → f ≐ g → ∀ {x y : X } → [ X ][ x ≡ y ] → [ A ][ iter {A} {X} < f > x ≈ iter {A} {X} < g > y ]
iter≈-resp-≐ {A} {X} f g f≐g {x} {y} x≡y with < f > x in eqa | < g > y in eqb
... | inj₁ a | inj₁ b = drop-inj₁ helper
where
helper : [ Delay≈.₀ A ⊎ₛ X ][ inj₁ a ≡ inj₁ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈.₀ A ⊎ₛ X) (cong f x≡y) f≐g
... | inj₁ a | inj₂ b = conflict (Delay≈.₀ A) X helper
where
helper : [ Delay≈.₀ A ⊎ₛ X ][ inj₁ a ≡ inj₂ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈.₀ A ⊎ₛ X) (cong f x≡y) f≐g
... | inj₂ a | inj₁ b = conflict (Delay≈.₀ A) X (≡-sym (Delay≈.₀ A ⊎ₛ X) helper)
where
helper : [ Delay≈.₀ A ⊎ₛ X ][ inj₂ a ≡ inj₁ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈.₀ A ⊎ₛ X) (cong f x≡y) f≐g
... | inj₂ a | inj₂ b = later≈ λ { .force≈ → iter≈-resp-≐ f g f≐g (drop-inj₂ helper) }
where
helper : [ Delay≈.₀ A ⊎ₛ X ][ inj₂ a ≡ inj₂ b ]
helper rewrite (≣-sym eqb) | (≣-sym eqa) = ≡-trans (Delay≈.₀ A ⊎ₛ X) (cong f x≡y) f≐g
-- Delay≈ together with iter yield an Elgot algebra
delay-algebras-on : ∀ {A : Setoid } → Elgot-Algebra-on (Delay≈.₀ A)
delay-algebras-on {A} = record
{ _# = iter≈ {A}
; #-Fixpoint = λ {X} {f} → iter≈-fixpoint {A} {X} {f}
; #-Uniformity = λ {X} {Y} {f} {g} {h} eq {x} → iter-uni {A} {X} {Y} {f} {g} {h} eq {x} {h ⟨$⟩ x} (≡-refl Y)
; #-Folding = λ {X} {Y} {f} {h} {x} → iter-folding {A} {X} {Y} {f} {h} {x}
; #-resp-≈ = λ {X} {f} {g} f≐g {x} → iter≈-resp-≐ {A} {X} f g f≐g {x} {x} (≡-refl X)
}
delay-algebras : ∀ (A : Setoid ) → Elgot-Algebra
delay-algebras A = record { A = Delay≈.₀ A ; algebra = delay-algebras-on {A}}
open Elgot-Algebra using (#-Fixpoint; #-Uniformity; #-Compositionality; #-resp-≈; #-Diamond) renaming (A to ⟦_⟧)
```
Next we show that these Elgot algebras are free.
This suffices to show that Delay≈ is an instance of K since stability follows from the fact that Setoids is a CCC.
We first define the free object lifting:
```agda
delay-lift : ∀ {A : Setoid } {B : Elgot-Algebra} → A ⟶ ⟦ B ⟧ → Elgot-Algebra-Morphism (delay-algebras A) B
delay-lift {A} {B} f = record { h = delay-lift≈ ; preserves = λ {X} {g} {x} → preserves' {X} {g} {x} }
where
open Elgot-Algebra B using (_#)
-- Setoid-morphism wrt strong bisimilarity
helper : (Delay.₀ A) ⟶ (⟦ B ⟧ ⊎ₛ Delay.₀ A)
< helper > (now x) = inj₁ (< f > x)
< helper > (later x) = inj₂ (force x)
cong helper (now x≡y) = inj₁ (cong f x≡y)
cong helper (later xy) = inj₂ (force xy)
```
helper # is the morphism we want, note that helper # is automatically a setoid morphism wrt strong bisimilarity.
The tricky part is showing that helper # is a setoid morphism wrt weak bisimilarity:
```agda
-- helper # is a setoid morphism wrt weak bisimilarity
delay-lift≈ : Delay≈.₀ A ⟶ ⟦ B ⟧
< delay-lift > = < helper # >
cong delay-lift≈ x≈y =
≡-trans ⟦ B ⟧
(cong (helper #) (-sym A (delta-prop₂ {A} ineq₂)))
(≡-trans ⟦ B ⟧
(≡-trans ⟦ B ⟧
(≡-sym ⟦ B ⟧ (helper#≈-cong' {z₂})) (≡-trans ⟦ B ⟧ (cong (helper #) (-trans A (delta-prop₁ (≈→≲ (≈-sym A x≈y))) (-sym A (-trans A (delta-prop₁ (≈→≲ x≈y)) (race-sym≈ x≈y))))) (helper#≈-cong' {z₁})))
(cong (helper #) (delta-prop₂ {A} ineq₁)))
where
ineq₁ = ≈→≲ {A} x≈y
ineq₂ = ≈→≲ {A} (≈-sym A x≈y)
z₁ = delta {A} ineq₁
z₂ = delta {A} ineq₂
helper#≈-cong' {z} = ≡-trans ⟦ B ⟧ (≡-trans ⟦ B ⟧ (≡-sym ⟦ B ⟧ eq₁) (≡-sym ⟦ B ⟧ eq₀)) eq₂
where
outer : A ⟶ (A ×ₛ -setoid {})
outer = record { to = λ z → z , zero ; cong = λ {x} {y} x≡y → x≡y , ≣-refl }
ι-cancel : ∀ {x} → [ A ][ (ι {A} ∘′ (λ z → z , zero)) x now x ]
ι-cancel = -refl A
helper₁' : Delay ( A × {}) → ⟦ B ⟧ ⊎ Delay ( A × {})
helper₁' (now (x , zero)) = inj₁ (< f > x)
helper₁' (now (x , suc n)) = inj₂ (< liftFₛ outer > (ι {A} (x , n)))
helper₁' (later y) = inj₂ (force y)
helper₁-cong' : {x y : Delay ( A × {})} → (xy : [ A ×ₛ -setoid ][ x y ]) → [ ⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid) ][ helper₁' x ≡ helper₁' y ]
helper₁-cong' {now (x , zero)} (now (x≡y , ≣-refl)) = inj₁ (cong f x≡y)
helper₁-cong' {now (x , suc n)} {now (y , suc _)} (now (x≡y , ≣-refl)) = inj₂ (cong (liftFₛ outer) (cong ιₛ' (x≡y , ≣-refl)))
helper₁-cong' (later xy) = inj₂ (force xy)
helper' : (Delay (A ×ₛ -setoid)) ⟶ (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
helper' = record { to = helper₁' ; cong = helper₁-cong'}
helper₁'' : Delay ( A × {}) → ⟦ B ⟧ ⊎ Delay ( A × {})
helper₁'' (now (x , _)) = inj₁ (< f > x)
helper₁'' (later y) = inj₂ (force y)
helper₁-cong'' : {x y : Delay ( A × {})} → (xy : [ A ×ₛ -setoid ][ x y ]) → [ ⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid) ][ helper₁'' x ≡ helper₁'' y ]
helper₁-cong'' {now (x , _)} (now (x≡y , ≣-refl)) = inj₁ (cong f x≡y)
helper₁-cong'' (later xy) = inj₂ (force xy)
helper'' : (Delay (A ×ₛ -setoid)) ⟶ (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
helper'' = record { to = helper₁'' ; cong = helper₁-cong''}
-- Needs #-Diamond
eq₀ : ∀ {z} → [ ⟦ B ⟧ ][ helper' # ⟨$⟩ z ≡ helper'' # ⟨$⟩ z ]
eq₀ {z} = ≡-trans ⟦ B ⟧
(#-resp-≈ B {Delay (A ×ₛ -setoid)} {helper'} step₁)
(≡-trans ⟦ B ⟧
(#-Diamond B {Delay (A ×ₛ -setoid)} helper''')
(#-resp-≈ B (λ {x} → (step₂ {x}))))
-- key special case
-- we prove it step-wise:
-- helper # ⟨$⟩ liftF proj₁ z ≡ helper'' # ⟨$⟩ z ≡ helper' # ⟨$⟩ z ≡ helper # ⟨$⟩ μ {A} (liftF (ι {A}) z)
helper#≈-cong' : {z : Delay ( A × )} → [ ⟦ B ⟧ ][ helper # ⟨$⟩ liftF proj₁ z ≡ helper # ⟨$⟩ μ {A} (liftF (ι {A}) z) ]
helper#≈-cong' {z} = ≡-trans ⟦ B ⟧ (≡-trans ⟦ B ⟧ (≡-sym ⟦ B ⟧ eq₁) (≡-sym ⟦ B ⟧ eq₀)) eq₂
where
helper₁''' : Delay ( A × {}) → ⟦ B ⟧ ⊎ (Delay ( A × {}) ⊎ Delay ( A × {}))
helper₁''' (now (x , zero)) = inj₁ (< f > x)
helper₁''' (now (x , suc n)) = inj₂ (inj₁ (< liftFₛ outer > (ι {A} (x , n))))
helper₁''' (later y) = inj₂ (inj₂ (force y))
-- insert value on left with 0 steps
outer : A ⟶ (A ×ₛ -setoid {})
< outer > z = (z , zero)
cong outer {x} {y} x≡y = (x≡y , ≣-refl)
helper₁-cong''' : {x y : Delay ( A × {})} → (xy : [ A ×ₛ -setoid ][ x y ]) → [ ⟦ B ⟧ ⊎ₛ (Delay (A ×ₛ -setoid) ⊎ₛ Delay (A ×ₛ -setoid)) ][ helper₁''' x ≡ helper₁''' y ]
helper₁-cong''' {now (x , zero)} (now (x≡y , ≣-refl)) = inj₁ (cong f x≡y)
helper₁-cong''' {now (x , suc n)} {now (y , suc _)} (now (x≡y , ≣-refl)) = inj₂ (inj₁ (cong (liftFₛ outer) (cong ιₛ' (x≡y , ≣-refl))))
helper₁-cong''' (later xy) = inj₂ (inj₂ (force xy))
helper''' : (Delay (A ×ₛ -setoid)) ⟶ (⟦ B ⟧ ⊎ₛ (Delay (A ×ₛ -setoid) ⊎ₛ Delay (A ×ₛ -setoid)))
helper''' = record { to = helper₁''' ; cong = helper₁-cong''' }
-- outer cancel ι
ι-cancel : (ι ∘ outer) ≐ η∼.η A
ι-cancel = -refl A
step₁ : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid) ][ helper' ⟨$⟩ x ≡ ([ inj₁ , inj₂ ∘′ [ id , id ] ] ∘′ helper₁''') x ]
step₁ {now (a , zero)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
step₁ {now (a , suc n)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
step₁ {later x} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
helper' : (Delay.₀ (A ×ₛ -setoid)) ⟶ (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
< helper' > (now (x , zero)) = inj₁ (< f > x)
< helper' > (now (x , suc n)) = inj₂ (< Delay. outer > (ι {A} (x , n)))
< helper' > (later y) = inj₂ (force y)
cong helper' {now (x , zero)} (now (x≡y , ≣-refl)) = inj₁ (cong f x≡y)
cong helper' {now (x , suc n)} {now (y , suc _)} (now (x≡y , ≣-refl)) = inj₂ (cong (Delay.₁ outer) (cong ι (x≡y , ≣-refl)))
cong helper' (later xy) = inj₂ (force xy)
step₂ : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid) ][ ([ inj₁ , [ inj₁ ∘′ < ([ inj₁ₛ , inj₂ₛ ∘ [ idₛ (Delay (A ×ₛ -setoid)) , idₛ (Delay (A ×ₛ -setoid)) ]ₛ ]ₛ ∘ helper''') # > , inj₂ ] ] ∘′ helper₁''') x ≡ helper'' ⟨$⟩ x ]
step₂ {now (a , zero)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
helper'' : (Delay.₀ (A ×ₛ -setoid)) ⟶ (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
< helper'' > (now (x , _)) = inj₁ (< f > x)
< helper'' > (later y) = inj₂ (force y)
cong helper'' {now (x , _)} (now (x≡y , ≣-refl)) = inj₁ (cong f x≡y)
cong helper'' (later xy) = inj₂ (force xy)
-- Follows by #-Diamond
eq₀ : ∀ {z} → [ ⟦ B ⟧ ][ helper' # ⟨$⟩ z ≡ helper'' # ⟨$⟩ z ]
eq₀ {z} = ≡-trans ⟦ B ⟧
(#-resp-≈ B {Delay.₀ (A ×ₛ -setoid)} {helper'} step₁)
(≡-trans ⟦ B ⟧
(#-Diamond B {Delay.₀ (A ×ₛ -setoid)} helper''')
(#-resp-≈ B (λ {x} → (step₂ {x}))))
where
helper''' : (Delay.₀ (A ×ₛ -setoid)) ⟶ (⟦ B ⟧ ⊎ₛ (Delay.₀ (A ×ₛ -setoid) ⊎ₛ Delay.₀ (A ×ₛ -setoid)))
< helper''' > (now (x , zero)) = inj₁ (< f > x)
< helper''' > (now (x , suc n)) = inj₂ (inj₁ (< Delay. outer > (ι {A} (x , n))))
< helper''' > (later y) = inj₂ (inj₂ (force y))
cong helper''' {now (x , zero)} (now (x≡y , ≣-refl)) = inj₁ (cong f x≡y)
cong helper''' {now (x , suc n)} {now (y , suc _)} (now (x≡y , ≣-refl)) = inj₂ (inj₁ (cong (Delay.₁ outer) (cong ι (x≡y , ≣-refl))))
cong helper''' (later xy) = inj₂ (inj₂ (force xy))
step₁ : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid) ][ helper' ⟨$⟩ x ≡ ([ inj₁ , inj₂ ∘′ [ id , id ] ] ∘′ < helper''' >) x ]
step₁ {now (a , zero)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
step₁ {now (a , suc n)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
step₁ {later x} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
step₂ : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid) ][ ([ inj₁ , [ inj₁ ∘′ < ([ inj₁ₛ , inj₂ₛ ∘ [ idₛ (Delay.₀ (A ×ₛ -setoid)) , idₛ (Delay.₀ (A ×ₛ -setoid)) ]ₛ ]ₛ ∘ helper''') # > , inj₂ ] ] ∘′ < helper''' >) x ≡ helper'' ⟨$⟩ x ]
step₂ {later y} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
step₂ {now (a , zero)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ (A ×ₛ -setoid))
step₂ {now (x , suc n)} = inj₁ (by-induction n)
where
by-induction : ∀ n → [ ⟦ B ⟧ ][ < ([ inj₁ₛ , inj₂ₛ ∘ [ idₛ (Delay (A ×ₛ -setoid)) , idₛ (Delay (A ×ₛ -setoid)) ]ₛ ]ₛ ∘ helper''') # > (< liftFₛ outer > (ι (x , n))) ≡ f ⟨$⟩ x ]
by-induction zero = #-Fixpoint B
by-induction (suc n) = ≡-trans ⟦ B ⟧ (#-Fixpoint B) (by-induction n)
step₂ {later y} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay (A ×ₛ -setoid))
by-induction : ∀ n → [ ⟦ B ⟧ ][ < ([ inj₁ₛ , inj₂ₛ ∘ [ idₛ (Delay.₀ (A ×ₛ -setoid)) , idₛ (Delay.₀ (A ×ₛ -setoid)) ]ₛ ]ₛ ∘ helper''') # > (< Delay. outer > (ι (x , n))) ≡ f ⟨$⟩ x ]
by-induction zero = #-Fixpoint B
by-induction (suc n) = ≡-trans ⟦ B ⟧ (#-Fixpoint B) (by-induction n)
eq₁ : ∀ {z} → [ ⟦ B ⟧ ][ helper'' # ⟨$⟩ z ≡ helper # ⟨$⟩ liftF proj₁ z ]
eq₁ {z} = #-Uniformity B {f = helper''} {g = helper} {h = liftFₛ proj₁ₛ} by-uni
where
by-uni : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay A ][ [ inj₁ , inj₂ ∘′ (liftF proj₁) ] (helper₁'' x) ≡ (< helper > ∘′ liftF proj₁) x ]
by-uni {now (a , b)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay A)
by-uni {later x} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay A)
eq : ∀ {x y} → [ A ×ₛ -setoid ][ x y ] → [ ⟦ B ⟧ ⊎ₛ Delay A ][ [ inj₁ , inj₂ ∘′ μ ∘′ (liftF ι) ] (helper₁' x) ≡ (helper₁ ∘′ μ ∘′ (liftF ι)) y ]
eq {now (x , n)} {now (y , .n)} (now (xy , ≣-refl)) = eq' {n}
where
eq' : ∀ {n} → [ ⟦ B ⟧ ⊎ₛ Delay A ][ [ inj₁ , inj₂ ∘′ μ ∘′ liftF ι ] (helper₁' (now (x , n))) ≡ (helper₁ ∘′ μ {A} ∘′ liftF ι) (now (y , n)) ]
eq' {zero} = inj₁ (cong f xy)
eq' {suc n} = inj₂ (-trans A (cong (μ≈∼ A) (-sym (Delay A) (lift-comp {f = outer} {g = ιₛ'} {ι (x , n)} (-refl A)))) (-trans A identityˡ (cong ιₛ' (xy , ≣-refl))))
eq (later xy) = inj₂ (cong (μ≈∼ A) (cong (liftFₛ ιₛ') (force xy)))
eq₂ : [ ⟦ B ⟧ ][ helper' # ⟨$⟩ z ≡ helper # ⟨$⟩ μ {A} (liftF (ι {A}) z)]
eq₂ = Elgot-Algebra.#-Uniformity B {Delay (A ×ₛ -setoid {})} {Delay A} {helper'} {helper} {μ≈∼ A ∘ liftFₛ ιₛ'} (λ {x} → eq {x} {x} (-refl (A ×ₛ -setoid)))
delay-lift' = record { to = < helper # > ; cong = helper#≈-cong }
-- interesting note:
-- the following definition prevents more general universe levels, i.e. we would like to parametrize this module by two levels c and , one for carriers and one for proofs.
-- but adopting this approach would force us to talk about setoids of type Setoid (c ⊔ ), this does not work with the definition below,
-- since propositional equality lives on the same level as values, this means the type below would have to look like:
-- ‖_‖ : Setoid c (c ⊔ ) → Setoid c c
-- this in turn does not play together nicely with later definition.
-- discretize a setoid
‖_‖ : Setoid → Setoid
_ ‖ X ‖ = X
[_][_≡_] ‖ X ‖ = _≡_
Setoid.isEquivalence ‖ X ‖ = Eq.isEquivalence
‖‖-quote : ∀ {X : Setoid } → ‖ X ‖ ⟶ X
_⟶_.to ‖‖-quote x = x
cong (‖‖-quote {X}) ≣-refl = ≡-refl X
disc-dom : ∀ {X : Setoid } → X ⟶ (Delay≈ A ⊎ₛ X) → ‖ X ‖ ⟶ (Delay A ⊎ₛ ‖ X ‖)
_⟶_.to (disc-dom f) x = f ⟨$⟩ x
cong (disc-dom {X} f) {x} {y} x≡y rewrite x≡y = ≡-refl (Delay A ⊎ₛ ‖ X ‖)
iter-g-var : ∀ {X : Setoid } → (g : X ⟶ (Delay≈ A ⊎ₛ X)) → ∀ {x} → [ A ][ (iter {A} {X} < g >) x (iterₛ {A} {‖ X ‖} (disc-dom g)) ⟨$⟩ x ]
iter-g-var : ∀ {X : Setoid } → (g : X ⟶ (Delay≈ A ⊎ₛ X)) → ∀ {x} → [ A ][ (iter {A} {X} < g >) x (iterₛ {A} {‖ X ‖} (disc-dom g)) ⟨$⟩ x ]
force (iter-g-var {X} g {x}) = iter-g-var {X} g {x}
iter-g-var {X} g {x} with g ⟨$⟩ x
... | inj₁ a = -refl A
... | inj₂ a = later (iter-g-var {X} g {a})
preserves' : ∀ {X : Setoid } {g : X ⟶ (Delay≈ A ⊎ₛ X)} → ∀ {x} → [ ⟦ B ⟧ ][ (delay-lift' ∘ (iterₛ {A} {X} g)) ⟨$⟩ x ≡ ([ inj₁ₛ ∘ delay-lift' , inj₂ₛ ]ₛ ∘ g) # ⟨$⟩ x ]
preserves' {X} {g} {x} = ≡-trans ⟦ B ⟧ step₁ step₂
where
step₁ : [ ⟦ B ⟧ ][ (delay-lift' ∘ (iterₛ {A} {X} g)) ⟨$⟩ x ≡ ([ inj₁ₛ ∘ (helper #) , inj₂ₛ ]ₛ ∘ (disc-dom g)) # ⟨$⟩ x ]
step₁ = ≡-trans ⟦ B ⟧ (≡-trans ⟦ B ⟧ (helper#-cong (iter-g-var g)) (sub-step₁ (disc-dom g) {inj₂ x})) (≡-sym ⟦ B ⟧ (#-Compositionality B {f = helper} {h = disc-dom g}))
where
sub-step₁ : (g : ‖ X ‖ ⟶ ((Delay A) ⊎ₛ ‖ X ‖)) → ∀ {x} → [ ⟦ B ⟧ ][ ((helper #) ∘ [ idₛ (Delay A) , iterₛ g ]ₛ) ⟨$⟩ x
≡ ([ [ inj₁ₛ , inj₂ₛ ∘ inj₁ₛ ]ₛ ∘ helper , inj₂ₛ ∘ inj₂ₛ ]ₛ ∘ [ inj₁ₛ , g ]ₛ) # ⟨$⟩ x ]
sub-step₁ g {u} = ≡-sym ⟦ B ⟧ (#-Uniformity B {h = [ idₛ (Delay A) , iterₛ g ]ₛ} (λ {y} → last-step {y}))
eq₁ : ∀ {z} → [ ⟦ B ⟧ ][ helper'' # ⟨$⟩ z ≡ helper # ⟨$⟩ liftF proj₁ z ]
eq₁ {z} = #-Uniformity B {f = helper''} {g = helper} {h = Delay.₁ proj₁ₛ} by-uni
where
last-step : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ (Delay A) ][ [ inj₁ₛ , inj₂ₛ ∘ [ idₛ (Delay A) , iterₛ g ]ₛ ]ₛ ∘ [ [ inj₁ₛ , inj₂ₛ ∘ inj₁ₛ ]ₛ ∘ helper , inj₂ₛ ∘ inj₂ₛ ]ₛ ∘ [ inj₁ₛ , g ]ₛ ⟨$⟩ x ≡ (helper ∘ [ idₛ (Delay A) , iterₛ g ]ₛ) ⟨$⟩ x ]
last-step {inj₁ (now a)} = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay A))
last-step {inj₁ (later a)} = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay A))
last-step {inj₂ a} with g ⟨$⟩ a in eqb
... | inj₁ (now b) = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay A))
... | inj₁ (later b) = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay A))
... | inj₂ b = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay A))
step₂ : [ ⟦ B ⟧ ][ ([ inj₁ₛ ∘ (helper #) , inj₂ₛ ]ₛ ∘ (disc-dom g)) # ⟨$⟩ x ≡ ([ inj₁ₛ ∘ delay-lift' , inj₂ₛ ]ₛ ∘ g) # ⟨$⟩ x ]
step₂ = #-Uniformity B {h = ‖‖-quote} sub-step₂
by-uni : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay.₀ A ][ [ inj₁ , inj₂ ∘′ (liftF proj₁) ] (< helper'' > x) ≡ (< helper > ∘′ liftF proj₁) x ]
by-uni {now (a , b)} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ A)
by-uni {later x} = ≡-refl (⟦ B ⟧ ⊎ₛ Delay.₀ A)
eq : ∀ {x y} → [ A ×ₛ -setoid ][ x y ] → [ ⟦ B ⟧ ⊎ₛ Delay.₀ A ][ [ inj₁ₛ , inj₂ₛ ∘ μ∼.η A ∘ (Delay.₁ ι) ]ₛ ∘ helper' ⟨$⟩ x ≡ (helper ∘ μ∼.η A ∘ (Delay.₁ ι)) ⟨$⟩ y ]
eq (later xy) = inj₂ (cong (μ∼.η A) (cong (Delay.₁ ι) (force xy)))
eq {now (x , n)} {now (y , .n)} (now (xy , ≣-refl)) = eq' {n}
where
-- helper for induction
eq' : ∀ {n} → [ ⟦ B ⟧ ⊎ₛ Delay.₀ A ][ [ inj₁ₛ , inj₂ₛ ∘ μ∼.η A ∘ (Delay.₁ ι) ]ₛ ∘ helper' ⟨$⟩ (now (x , n)) ≡ (helper ∘ μ∼.η A ∘ (Delay.₁ ι)) ⟨$⟩ (now (y , n)) ]
eq' {zero} = inj₁ (cong f xy)
eq' {suc n} = inj₂ (-trans A (cong (μ∼.η A) (-sym (Delay.₀ A) (Delay.homomorphism {f = outer} {g = ι} {ι (x , n)}))) (-trans A identityˡ (cong ι (xy , ≣-refl))))
eq₂ : [ ⟦ B ⟧ ][ helper' # ⟨$⟩ z ≡ helper # ⟨$⟩ μ {A} (liftF (ι {A}) z) ]
eq₂ = Elgot-Algebra.#-Uniformity B {Delay.₀ (A ×ₛ -setoid {})} {Delay.₀ A} {helper'} {helper} {μ∼.η A ∘ Delay.₁ ι} (λ {x} → eq {x} {x} (-refl (A ×ₛ -setoid)))
```
To show preservation we need some facts about discretizing setoids:
```agda
-- interesting note:
-- the following definition prevents more general universe levels, i.e. we would like to parametrize this module by two levels c and , one for carriers and one for proofs.
-- but adopting this approach would force us to talk about setoids of type Setoid (c ⊔ ), this does not work with the definition below,
-- since propositional equality lives on the same level as values, this means the type below would have to look like:
-- ‖_‖ : Setoid c (c ⊔ ) → Setoid c c
-- this in turn does not play together nicely with later definition.
-- discretize a setoid
‖_‖ : Setoid → Setoid
_ ‖ X ‖ = X
[_][_≡_] ‖ X ‖ = _≡_
Setoid.isEquivalence ‖ X ‖ = Eq.isEquivalence
‖‖-quote : ∀ {X : Setoid } → ‖ X ‖ ⟶ X
_⟶_.to ‖‖-quote x = x
cong (‖‖-quote {X}) ≣-refl = ≡-refl X
disc-dom : ∀ {X : Setoid } → X ⟶ (Delay≈.₀ A ⊎ₛ X) → ‖ X ‖ ⟶ (Delay.₀ A ⊎ₛ ‖ X ‖)
_⟶_.to (disc-dom f) x = f ⟨$⟩ x
cong (disc-dom {X} f) {x} {y} x≡y rewrite x≡y = ≡-refl (Delay.₀ A ⊎ₛ ‖ X ‖)
iter-g-var : ∀ {X : Setoid } → (g : X ⟶ (Delay≈.₀ A ⊎ₛ X)) → ∀ {x} → [ A ][ (iter {A} {X} < g >) x (iter {A} {‖ X ‖} (disc-dom g)) ⟨$⟩ x ]
iter-g-var : ∀ {X : Setoid } → (g : X ⟶ (Delay≈.₀ A ⊎ₛ X)) → ∀ {x} → [ A ][ (iter {A} {X} < g >) x (iter {A} {‖ X ‖} (disc-dom g)) ⟨$⟩ x ]
force (iter-g-var {X} g {x}) = iter-g-var {X} g {x}
iter-g-var {X} g {x} with g ⟨$⟩ x
... | inj₁ a = -refl A
... | inj₂ a = later (iter-g-var {X} g {a})
```
Now we show that helper # is iteration preserving:
```agda
preserves' : ∀ {X : Setoid } {g : X ⟶ (Delay≈.₀ A ⊎ₛ X)} → ∀ {x} → [ ⟦ B ⟧ ][ (delay-lift≈ ∘ (iter≈ {A} {X} g)) ⟨$⟩ x ≡ ([ inj₁ₛ ∘ delay-lift≈ , inj₂ₛ ]ₛ ∘ g) # ⟨$⟩ x ]
preserves' {X} {g} {x} = ≡-trans ⟦ B ⟧ step₁ step₂
where
sub-step₂ : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ X ][([ inj₁ₛ , inj₂ₛ ]ₛ ∘ ([ inj₁ₛ ∘ (helper #) , inj₂ₛ ]ₛ ∘ (disc-dom g))) ⟨$⟩ x ≡ ([ inj₁ₛ ∘ delay-lift' , inj₂ₛ ]ₛ ∘ g) ⟨$⟩ x ]
step₁ : [ ⟦ B ⟧ ][ (delay-lift≈ ∘ (iter≈ {A} {X} g)) ⟨$⟩ x ≡ ([ inj₁ₛ ∘ (helper #) , inj₂ₛ ]ₛ ∘ (disc-dom g)) # ⟨$⟩ x ]
step₁ = ≡-trans ⟦ B ⟧ (≡-trans ⟦ B ⟧ (cong (helper #) (iter-g-var g)) (sub-step₁ (disc-dom g) {inj₂ x})) (≡-sym ⟦ B ⟧ (#-Compositionality B {f = helper} {h = disc-dom g}))
where
sub-step₁ : (g : ‖ X ‖ ⟶ ((Delay.₀ A) ⊎ₛ ‖ X ‖)) → ∀ {x} → [ ⟦ B ⟧ ][ ((helper #) ∘ [ idₛ (Delay.₀ A) , iter g ]ₛ) ⟨$⟩ x
≡ ([ [ inj₁ₛ , inj₂ₛ ∘ inj₁ₛ ]ₛ ∘ helper , inj₂ₛ ∘ inj₂ₛ ]ₛ ∘ [ inj₁ₛ , g ]ₛ) # ⟨$⟩ x ]
sub-step₁ g {u} = ≡-sym ⟦ B ⟧ (#-Uniformity B {h = [ idₛ (Delay.₀ A) , iter g ]ₛ} (λ {y} → last-step {y}))
where
last-step : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ (Delay.₀ A) ][ [ inj₁ₛ , inj₂ₛ ∘ [ idₛ (Delay.₀ A) , iter g ]ₛ ]ₛ ∘ [ [ inj₁ₛ , inj₂ₛ ∘ inj₁ₛ ]ₛ ∘ helper , inj₂ₛ ∘ inj₂ₛ ]ₛ ∘ [ inj₁ₛ , g ]ₛ ⟨$⟩ x ≡ (helper ∘ [ idₛ (Delay.₀ A) , iter g ]ₛ) ⟨$⟩ x ]
last-step {inj₁ (now a)} = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay.₀ A))
last-step {inj₁ (later a)} = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay.₀ A))
last-step {inj₂ a} with g ⟨$⟩ a in eqb
... | inj₁ (now b) = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay.₀ A))
... | inj₁ (later b) = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay.₀ A))
... | inj₂ b = ≡-refl (⟦ B ⟧ ⊎ₛ (Delay.₀ A))
step₂ : [ ⟦ B ⟧ ][ ([ inj₁ₛ ∘ (helper #) , inj₂ₛ ]ₛ ∘ (disc-dom g)) # ⟨$⟩ x ≡ ([ inj₁ₛ ∘ delay-lift≈ , inj₂ₛ ]ₛ ∘ g) # ⟨$⟩ x ]
step₂ = #-Uniformity B {h = ‖‖-quote} sub-step₂
where
sub-step₂ : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ X ][([ inj₁ₛ , inj₂ₛ ]ₛ ∘ ([ inj₁ₛ ∘ (helper #) , inj₂ₛ ]ₛ ∘ (disc-dom g))) ⟨$⟩ x ≡ ([ inj₁ₛ ∘ delay-lift≈ , inj₂ₛ ]ₛ ∘ g) ⟨$⟩ x ]
sub-step₂ {x} with g ⟨$⟩ x
... | inj₁ y = ≡-refl (⟦ B ⟧ ⊎ₛ X)
... | inj₂ y = ≡-refl (⟦ B ⟧ ⊎ₛ X)
open Elgot-Algebra-Morphism using (preserves) renaming (h to <<_>>)
```
open Elgot-Algebra-Morphism using (preserves) renaming (h to <<_>>)
Only uniqueness of delaylift is left now:
freeAlgebra : ∀ (A : Setoid ) → FreeObject elgotForgetfulF A
freeAlgebra A = record
{ FX = delay-algebras A
; η = η≈ A
; _* = delay-lift
; *-lift = λ {B} f {x} → Elgot-Algebra.#-Fixpoint B
; *-uniq = λ {B} f g eq {x} → *-uniq' {B} f g (delay-lift f) eq (#-Fixpoint B) {x}
}
where
```agda
freeAlgebra : ∀ (A : Setoid ) → FreeObject elgotForgetfulF A
freeAlgebra A = record
{ FX = delay-algebras A
; η = η≈.η A
; _* = delay-lift
; *-lift = λ {B} f {x} → Elgot-Algebra.#-Fixpoint B
; *-uniq = λ {B} f g eq {x} → *-uniq' {B} f g (delay-lift f) eq (#-Fixpoint B) {x}
}
where
*-uniq' : ∀ {B : Elgot-Algebra} (f : A ⟶ ⟦ B ⟧) (g h : Elgot-Algebra-Morphism (delay-algebras A) B)
→ (<< g >> ∘ (η≈ A)) ≐ f
→ (<< h >> ∘ (η≈ A)) ≐ f
→ (<< g >> ∘ (η≈ A)) ≐ f
→ (<< h >> ∘ (η≈ A)) ≐ f
<< g >> ≐ << h >>
*-uniq' {B} f g h eqᵍ eqʰ {x} = ≡-trans ⟦ B ⟧ (cong << g >> iter-id)
(≡-trans ⟦ B ⟧ (preserves g {Delay A} {[ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now} {x = x})
(≡-trans ⟦ B ⟧ (#-resp-≈ B (λ {x} → helper-eq' {x}) {x})
(≡-trans ⟦ B ⟧ (≡-sym ⟦ B ⟧ (preserves h {Delay A} {[ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now} {x = x}))
(≡-trans ⟦ B ⟧ (preserves g {Delay.₀ A} {[ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now} {x = x})
(≡-trans ⟦ B ⟧ (#-resp-≈ B (λ {x} → helper-eq' {x}) {x})
(≡-trans ⟦ B ⟧ (≡-sym ⟦ B ⟧ (preserves h {Delay.₀ A} {[ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now} {x = x}))
(≡-sym ⟦ B ⟧ (cong << h >> iter-id)))))
where
open Elgot-Algebra B using (_#)
D⇒D≈ : ∀ {A : Setoid } → Delay A ⟶ Delay≈ A
D⇒D≈ : ∀ {A : Setoid } → Delay.₀ A ⟶ Delay≈.₀ A
D⇒D≈ {A} = record { to = λ x → x ; cong = λ eq → ∼⇒≈ eq }
helper-now₁ : (Delay A ) → (Delay A ⊎ (Delay A ))
helper-now₁ (now x) = inj₁ (now x)
helper-now₁ (later x) = inj₂ (force x)
helper-now : Delay A ⟶ ((Delay A) ⊎ₛ (Delay A))
helper-now = record { to = helper-now₁ ; cong = λ { (now eq) → inj₁ (now eq)
; (later eq) → inj₂ (force eq) } }
-- setoid morphism that unfolds a computation (works like 'out') but lifts the value to a computation
-- the point of this definition is that 'helper-now # = id'
helper-now : Delay.₀ A ⟶ ((Delay.₀ A) ⊎ₛ (Delay.₀ A))
< helper-now > (now x) = inj₁ (now x)
< helper-now > (later x) = inj₂ (force x)
cong helper-now (now eq) = inj₁ (now eq)
cong helper-now (later eq) = inj₂ (force eq)
helper-eq' : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay A ][ ([ inj₁ₛ ∘ << g >> , inj₂ₛ ]ₛ ∘ [ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x
≡ ([ inj₁ₛ ∘ << h >> , inj₂ₛ ]ₛ ∘ [ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x ]
helper-eq' {now x} = inj₁ (≡-trans ⟦ B ⟧ eqᵍ (≡-sym ⟦ B ⟧ eqʰ))
iter-id : ∀ {x} → [ A ][ x ≈ iter≈ ([ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x ]
iter-id {now x} = ≈-refl A
iter-id {later x} = later≈ λ { .force≈ → iter-id }
-- the 'meat' of this proof:
helper-eq' : ∀ {x} → [ ⟦ B ⟧ ⊎ₛ Delay.₀ A ][ ([ inj₁ₛ ∘ << g >> , inj₂ₛ ]ₛ ∘ [ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x
≡ ([ inj₁ₛ ∘ << h >> , inj₂ₛ ]ₛ ∘ [ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x ]
helper-eq' {now x} = inj₁ (≡-trans ⟦ B ⟧ eqᵍ (≡-sym ⟦ B ⟧ eqʰ))
helper-eq' {later x} = inj₂ (-refl A)
iter-id : ∀ {x} → [ A ][ x ≈ iterₛ ([ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x ]
iter-id : ∀ {x} → [ A ][ x ≈′ iterₛ ([ inj₁ₛ ∘ D⇒D≈ , inj₂ₛ ]ₛ ∘ helper-now) ⟨$⟩ x ]
force≈ (iter-id {x}) = iter-id {x}
iter-id {now x} = ≈-refl A
iter-id {later x} = later≈ (iter-id {force x})
-- stability follows automatically since Setoids is cartesian closed
open CartesianClosed (Setoids-CCC ) renaming (exp to setoid-exp)
open import Algebra.Elgot.Properties distributive setoid-exp using (free-isStable)

View file

@ -11,6 +11,8 @@ open import Data.Product using (_,_)
```
-->
# (Strong) Pre-Elgot monads
```agda
module Monad.PreElgot {o e} (ambient : Ambient o e) where
open Ambient ambient
@ -20,7 +22,7 @@ module Monad.PreElgot {o e} (ambient : Ambient o e) where
open import Algebra.Elgot cocartesian
```
# (strong) pre-Elgot monads
A monad **T** is a pre-Elgot monad if every `TX` admits an Elgot algebra structure
```agda
record IsPreElgot (T : Monad C) : Set (o ⊔ ⊔ e) where
@ -45,7 +47,11 @@ module Monad.PreElgot {o e} (ambient : Ambient o e) where
isPreElgot : IsPreElgot T
open IsPreElgot isPreElgot public
```
A strong monad **T** is a strong pre-Elgot monad if it is a pre-Elgot monad and strength is iteration preserving
```agda
record IsStrongPreElgot (SM : StrongMonad monoidal) : Set (o ⊔ ⊔ e) where
open StrongMonad SM using (M; strengthen)
open Monad M using (F)