open import Categories.Category.Core
open import Categories.Object.Product.Core using (Product)
open import Categories.Object.Terminal
open import Categories.Monad hiding (id)
open import Categories.Monad.Relative renaming (Monad to RMonad)
open import Categories.Functor.Core
open import Categories.Monad.Strong
open import Categories.Category.Distributive
open import Categories.NaturalTransformation using (NaturalTransformation)
open import Categories.Functor using (_∘F_) renaming (id to Id)
open import Categories.Functor.Bifunctor using (reduce-×; overlap-×)
open import Data.Product using (_,_)
open import Monad.Instance.Delay
open import Monad.Helper
import Categories.Morphism as Mor
import Categories.Morphism.Reasoning as MR
import Categories.Morphism.Properties as MP
import Categories.Morphism.Regular.Properties as MRP
import Categories.Morphism.Regular as MRR
module Monad.Instance.Delay.Zip {o ℓ e} {C : Category o ℓ e} (distributive : Distributive C) (D : DelayM (Distributive.cocartesian distributive)) where
open Category C
open import Category.Distributive.Helper distributive
open import Categories.Diagram.Pullback C
open import Monad.Instance.Delay.Commutative distributive D
open τ-mod
open σ-mod
open HomReasoning
open Equiv
open Mor C
open MRR C
open MRP C
open import Categories.Morphism.Properties C
open MR C
open MP C
open DelayM D
open import Monad.Instance.Delay.Guarded cocartesian D
open D-Kleisli
open D-Monad
module F = D.F
open F using (homomorphism; F-resp-≈; identity)
open D.μ renaming (η to μ)
open D-Strong
zip₁⁻¹ : ∀ {X Y} → D₀ (X × Y + (X × D₀ Y + D₀ X × Y)) ⇒ D₀ X
zip₁⁻¹ = extend [ now ∘ π₁ , out⁻¹ ∘ (π₁ +₁ π₁) ]
zip₂⁻¹ : ∀ {X Y} → D₀ (X × Y + (X × D₀ Y + D₀ X × Y)) ⇒ D₀ Y
zip₂⁻¹ = extend [ now ∘ π₂ , out⁻¹ ∘ [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ]
zip⁻¹ : ∀ {X Y} → D₀ (X × Y + (X × D₀ Y + D₀ X × Y)) ⇒ D₀ X × D₀ Y
zip⁻¹ = ⟨ zip₁⁻¹ , zip₂⁻¹ ⟩
zip : ∀ {X Y} → D₀ X × D₀ Y ⇒ D₀ (X × Y + (X × D₀ Y + D₀ X × Y))
zip = Coit.coit (distr ∘ (out ⁂ out ))
zip-natural : NaturalTransformation (reduce-× -×- D.F D.F) (D.F ∘F overlap-× -+- -×- (overlap-× -+- (reduce-× -×- Id D.F) (reduce-× -×- D.F Id)))
zip-natural .NaturalTransformation.η _ = zip
zip-natural .NaturalTransformation.commute (f , g) = Coit.coit-unique'
(((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ id) ∘ distr ∘ (out ⁂ out ))
(zip ∘ (D₁ f ⁂ D₁ g))
(D₁(f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) ∘ zip)
(begin
out ∘ zip ∘ (D₁ f ⁂ D₁ g)
≈⟨ pullˡ (Coit.coit-commutes _) ⟩
((id +₁ zip) ∘ distr ∘ (out ⁂ out)) ∘ (D₁ f ⁂ D₁ g)
≈⟨ pullʳ (pullʳ (⁂∘⁂ ○ ⁂-cong₂ (D₁-commutes _) (D₁-commutes _))) ⟩
(id +₁ zip) ∘ distr ∘ ((f +₁ D₁ f) ∘ out ⁂ (g +₁ D₁ g) ∘ out)
≈⟨ refl⟩∘⟨ refl⟩∘⟨ ⁂∘⁂ ⟨
(id +₁ zip) ∘ distr ∘ ((f +₁ D₁ f) ⁂ (g +₁ D₁ g)) ∘ (out ⁂ out)
≈⟨ refl⟩∘⟨ extendʳ (distr-natural f g (D₁ f) (D₁ g)) ⟩
(id +₁ zip) ∘ ((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ D₁ f ⁂ D₁ g) ∘ distr ∘ (out ⁂ out)
≈⟨ pullˡ (+₁∘+₁ ○ +₁-cong₂ identityˡ refl) ⟩
((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ zip ∘ (D₁ f ⁂ D₁ g)) ∘ distr ∘ (out ⁂ out)
≈⟨ pullˡ (+₁∘+₁ ○ +₁-cong₂ identityˡ identityʳ) ⟨
(id +₁ zip ∘ (D₁ f ⁂ D₁ g)) ∘ ((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ id) ∘ distr ∘ (out ⁂ out)
∎)
(begin
out ∘ D₁ (f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) ∘ zip ≈⟨ pullˡ (D₁-commutes _) ⟩
(((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ D₁ (f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g)) ∘ out) ∘ zip ≈⟨ pullʳ (Coit.coit-commutes _) ⟩
((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ D₁ (f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g)) ∘ (id +₁ zip) ∘ distr ∘ (out ⁂ out) ≈⟨ pullˡ (+₁∘+₁ ○ +₁-cong₂ identityʳ refl) ⟩
((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ D₁ (f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) ∘ zip) ∘ distr ∘ (out ⁂ out) ≈⟨ pullˡ (+₁∘+₁ ○ +₁-cong₂ identityˡ identityʳ) ⟨
(id +₁ D₁ (f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) ∘ zip) ∘ ((f ⁂ g +₁ f ⁂ D₁ g +₁ D₁ f ⁂ g) +₁ id) ∘ distr ∘ (out ⁂ out)
∎)
zip-natural .NaturalTransformation.sym-commute (f , g) = sym (zip-natural .NaturalTransformation.commute (f , g))
fst-via-# : ∀ {X Y} → (f# : D₀ X × D₀ Y ⇒ D₀ X) → (out ∘ f# ≈ (π₁ +₁ [ π₁ , f# ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹ ∘ (out ⁂ out)) → f# ≈ π₁
fst-via-# {X}{Y} f# eq = guarded-unique (out⁻¹ ∘ (i₁ +₁ id) ∘ f) f# π₁ (record { guard = f ; guard-eq = introˡ out∘out⁻¹ ○ assoc}) (fp-helper f# eq) fp
where
f = (π₁ +₁ [ (D₁ i₁) ∘ π₁ , now ∘ i₂ ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
fp-helper : (g : D₀ X × D₀ Y ⇒ D₀ X)
→ (out ∘ g ≈ (π₁ +₁ [ π₁ , g ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹ ∘ (out ⁂ out))
→ g ≈ extend [ now , g ] ∘ (out⁻¹ ∘ (i₁ +₁ id) ∘ f)
fp-helper g eq = out-mono g (extend [ now , g ] ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f)
(begin
out ∘ g
≈⟨ eq ⟩
[ i₁ ∘ π₁ , i₂ ∘ [ π₁ , g ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ []-cong₂ refl (∘-resp-≈ʳ (∘-resp-≈ˡ ([]-cong₂ (elimˡ (extend-≈ inject₁ ○ DK.identityˡ)) inject₂))) ⟩∘⟨refl ⟩
[ i₁ ∘ π₁ , i₂ ∘ [ extend ([ now , g ] ∘ i₁) ∘ π₁ , [ now , g ] ∘ i₂ ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ []-cong₂ refl (∘-resp-≈ʳ (∘-resp-≈ˡ ([]-cong₂ (pullˡ (extend∘F₁' kleisli [ now , g ] i₁)) (pullˡ DK.identityʳ)))) ⟩∘⟨refl ⟩
[ i₁ ∘ π₁ , i₂ ∘ [ extend [ now , g ] ∘ (D₁ i₁) ∘ π₁ , extend [ now , g ] ∘ now ∘ i₂ ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ []-cong₂ refl (pullʳ (pullˡ ∘[])) ⟩∘⟨refl ⟩
[ i₁ ∘ π₁ , (i₂ ∘ extend [ now , g ]) ∘ [ (D₁ i₁) ∘ π₁ , now ∘ i₂ ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ pullˡ []∘+₁ ⟩
[ i₁ , i₂ ∘ extend [ now , g ] ] ∘ f
≈˘⟨ []-cong₂ unitlaw refl ⟩∘⟨refl ⟩
[ out ∘ now , i₂ ∘ extend [ now , g ] ] ∘ f
≈˘⟨ []-cong₂ (pullʳ inject₁) identityʳ ⟩∘⟨refl ⟩
[ (out ∘ [ now , g ]) ∘ i₁ , (i₂ ∘ extend [ now , g ]) ∘ id ] ∘ f
≈˘⟨ pullˡ []∘+₁ ⟩
[ out ∘ [ now , g ] , i₂ ∘ extend [ now , g ] ] ∘ (i₁ +₁ id) ∘ f
≈˘⟨ pullˡ (cancelʳ out∘out⁻¹) ⟩
([ out ∘ [ now , g ] , i₂ ∘ extend [ now , g ] ] ∘ out) ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f
≈˘⟨ pullˡ (extend-commutes [ now , g ]) ⟩
out ∘ extend [ now , g ] ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f
∎)
fp = fp-helper π₁
(begin
out ∘ π₁ ≈⟨ sym project₁ ⟩
π₁ ∘ (out ⁂ out) ≈⟨ pullˡ distributeʳ⁻¹-π₁ ⟨
(π₁ +₁ π₁) ∘ distributeʳ⁻¹ ∘ (out ⁂ out) ≈⟨ +₁-cong₂ refl (sym distributeˡ⁻¹-π₁) ⟩∘⟨refl ⟩
(π₁ +₁ [ π₁ , π₁ ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
∎)
snd-via-# : ∀ {X Y} → (f# : D₀ X × D₀ Y ⇒ D₀ Y) → (out ∘ f# ≈ [ π₂ , (π₂ +₁ f#) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)) → f# ≈ π₂
snd-via-# {X}{Y} f# eq = guarded-unique (out⁻¹ ∘ (i₁ +₁ id) ∘ f) f# π₂ (record { guard = f ; guard-eq = sym (cancelˡ out∘out⁻¹)}) (fp-helper f# eq) fp
where
f = [ (id +₁ D₁ i₁) ∘ π₂ , (π₂ +₁ now ∘ i₂) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
fp-helper : (g : D₀ X × D₀ Y ⇒ D₀ Y)
→ (out ∘ g ≈ [ π₂ , (π₂ +₁ g) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out))
→ g ≈ extend [ now , g ] ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f
fp-helper g eq = out-mono g (extend [ now , g ] ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f)
(begin
out ∘ g
≈⟨ eq ⟩
[ π₂ , (π₂ +₁ g) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ []-cong₂ (elimˡ ([]-cong₂ identityʳ (elimʳ (extend∘F₁' kleisli [ now , g ] i₁ ○ extend-≈ inject₁ ○ DK.identityˡ)) ○ +-η)) refl ⟩∘⟨refl ⟩
[ (id +₁ extend [ now , g ] ∘ D₁ i₁) ∘ π₂ , (π₂ +₁ g) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ []-cong₂ refl (∘-resp-≈ˡ (+₁-cong₂ identityˡ (pullˡ DK.identityʳ ○ inject₂))) ⟩∘⟨refl ⟩
[ (id +₁ (extend [ now , g ]) ∘ D₁ i₁) ∘ π₂ , (id ∘ π₂ +₁ extend [ now , g ] ∘ now ∘ i₂) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ pullˡ (∘[] ○ []-cong₂ (pullˡ (+₁∘+₁ ○ +₁-cong₂ identityˡ refl)) (pullˡ +₁∘+₁)) ⟩
(id +₁ extend [ now , g ]) ∘ f
≈˘⟨ []-cong₂ (trans unitlaw (sym identityʳ)) refl ⟩∘⟨refl ⟩
[ out ∘ now , i₂ ∘ extend [ now , g ] ] ∘ f
≈˘⟨ []-cong₂ (pullʳ inject₁) identityʳ ⟩∘⟨refl ⟩
[ (out ∘ [ now , g ]) ∘ i₁ , (i₂ ∘ extend [ now , g ]) ∘ id ] ∘ f
≈˘⟨ pullˡ []∘+₁ ⟩
[ out ∘ [ now , g ] , i₂ ∘ extend [ now , g ] ] ∘ (i₁ +₁ id) ∘ f
≈˘⟨ pullˡ (cancelʳ out∘out⁻¹) ⟩
([ out ∘ [ now , g ] , i₂ ∘ extend [ now , g ] ] ∘ out) ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f
≈˘⟨ pullˡ (extend-commutes [ now , g ]) ⟩
out ∘ extend [ now , g ] ∘ out⁻¹ ∘ (i₁ +₁ id) ∘ f
∎)
fp = fp-helper π₂
(begin
out ∘ π₂ ≈⟨ sym project₂ ⟩
π₂ ∘ (out ⁂ out) ≈˘⟨ pullˡ distributeʳ⁻¹-π₂ ⟩
[ π₂ , π₂ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out) ≈⟨ []-cong₂ refl (sym distributeˡ⁻¹-π₂) ⟩∘⟨refl ⟩
[ π₂ , (π₂ +₁ π₂) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
∎)
zip⁻¹∘zip : ∀ {X Y} → zip⁻¹ {X}{Y} ∘ zip {X}{Y} ≈ id
zip⁻¹∘zip = ⟨⟩-unique′
(trans (fst-via-# (π₁ ∘ zip⁻¹ ∘ zip) zip⁻¹∘zip-rec₁) (sym identityʳ))
(trans (snd-via-# (π₂ ∘ zip⁻¹ ∘ zip) zip⁻¹∘zip-rec₂) (sym identityʳ))
where
zip⁻¹∘zip-rec₁ : out ∘ π₁ ∘ zip⁻¹ ∘ zip ≈ (π₁ +₁ [ π₁ , π₁ ∘ zip⁻¹ ∘ zip ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
zip⁻¹∘zip-rec₁ =
begin
out ∘ π₁ ∘ zip⁻¹ ∘ zip
≈⟨ refl⟩∘⟨ pullˡ project₁ ⟩
out ∘ zip₁⁻¹ ∘ zip
≈⟨ pullˡ (extend-commutes [ now ∘ π₁ , out⁻¹ ∘ (π₁ +₁ π₁) ]) ⟩
([ out ∘ [ now ∘ π₁ , out⁻¹ ∘ (π₁ +₁ π₁) ] , i₂ ∘ zip₁⁻¹ ] ∘ out) ∘ zip
≈⟨ []-cong₂ (∘[] ○ []-cong₂ (pullˡ unitlaw) (cancelˡ out∘out⁻¹)) refl ⟩∘⟨refl ⟩∘⟨refl ⟩
([ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , i₂ ∘ zip₁⁻¹ ] ∘ out) ∘ zip
≈⟨ pullʳ (Coit.coit-commutes (distr ∘ (out ⁂ out))) ⟩
[ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , i₂ ∘ zip₁⁻¹ ] ∘ (id +₁ zip) ∘ distr ∘ (out ⁂ out)
≈⟨ pullˡ ([]∘+₁ ○ []-cong₂ identityʳ refl) ⟩
[ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , (i₂ ∘ zip₁⁻¹) ∘ zip ] ∘ distr ∘ (out ⁂ out)
≈⟨ pullˡ (pullˡ (∘[] ○ []-cong₂ (pullˡ inject₁) (pullˡ ([]∘+₁ ○ []-cong₂ (pullˡ inject₂ ○ inject₂) identityʳ )))) ⟩
([ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] ∘ (id +₁ i₁) ∘ distributeˡ⁻¹ , [ i₂ ∘ π₁ , (i₂ ∘ zip₁⁻¹) ∘ zip ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹) ∘ (out ⁂ out)
≈⟨ []-cong₂ (pullˡ ([]∘+₁ ○ []-cong₂ identityʳ inject₁)) refl ⟩∘⟨refl ⟩∘⟨refl ⟩
([ [ i₁ ∘ π₁ , i₁ ∘ π₁ ] ∘ distributeˡ⁻¹ , [ i₂ ∘ π₁ , (i₂ ∘ zip₁⁻¹) ∘ zip ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹) ∘ (out ⁂ out)
≈⟨ []-cong₂ ((∘-resp-≈ˡ (sym ∘[])) ○ pullʳ distributeˡ⁻¹-π₁) (∘-resp-≈ˡ ([]-cong₂ refl assoc ○ sym ∘[])) ⟩∘⟨refl ⟩∘⟨refl ⟩
([ i₁ ∘ π₁ , (i₂ ∘ [ π₁ , zip₁⁻¹ ∘ zip ]) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹) ∘ (out ⁂ out)
≈⟨ []-cong₂ refl (pullʳ (∘-resp-≈ˡ ([]-cong₂ refl (pushˡ (sym project₁))))) ⟩∘⟨refl ⟩∘⟨refl ⟩
((π₁ +₁ [ π₁ , π₁ ∘ zip⁻¹ ∘ zip ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹) ∘ (out ⁂ out)
≈⟨ assoc ⟩
(π₁ +₁ [ π₁ , π₁ ∘ zip⁻¹ ∘ zip ] ∘ distributeˡ⁻¹) ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
∎
zip⁻¹∘zip-rec₂ : out ∘ π₂ ∘ zip⁻¹ ∘ zip ≈ [ π₂ , (π₂ +₁ π₂ ∘ zip⁻¹ ∘ zip) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
zip⁻¹∘zip-rec₂ =
begin
out ∘ π₂ ∘ zip⁻¹ ∘ zip
≈⟨ refl⟩∘⟨ pullˡ project₂ ⟩
out ∘ zip₂⁻¹ ∘ zip
≈⟨ pullˡ (extend-commutes [ now ∘ π₂ , out⁻¹ ∘ [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ]) ⟩
([ out ∘ [ now ∘ π₂ , out⁻¹ ∘ [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ∘ out) ∘ zip
≈⟨ []-cong₂ (∘[] ○ []-cong₂ (pullˡ unitlaw) (cancelˡ out∘out⁻¹)) refl ⟩∘⟨refl ⟩∘⟨refl ⟩
([ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ∘ out) ∘ zip
≈⟨ pullʳ (Coit.coit-commutes (distr ∘ (out ⁂ out))) ⟩
[ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ∘ (id +₁ zip) ∘ distr ∘ (out ⁂ out)
≈⟨ pullˡ ([]∘+₁ ○ []-cong₂ identityʳ refl) ⟩
[ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , (i₂ ∘ zip₂⁻¹) ∘ zip ] ∘ distr ∘ (out ⁂ out)
≈⟨ pullˡ (pullˡ (∘[] ○ []-cong₂ (pullˡ inject₁) (pullˡ ([]∘+₁ ○ []-cong₂ (pullˡ inject₂ ○ inject₂) identityʳ )))) ⟩
([ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] ∘ (id +₁ i₁) ∘ distributeˡ⁻¹ , [ i₁ ∘ π₂ , (i₂ ∘ zip₂⁻¹) ∘ zip ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹) ∘ (out ⁂ out)
≈⟨ assoc ⟩
[ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] ∘ (id +₁ i₁) ∘ distributeˡ⁻¹ , [ i₁ ∘ π₂ , (i₂ ∘ zip₂⁻¹) ∘ zip ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈⟨ []-cong₂ (pullˡ ([]∘+₁ ○ []-cong₂ identityʳ inject₁)) refl ⟩∘⟨refl ⟩
[ [ i₁ ∘ π₂ , i₂ ∘ π₂ ] ∘ distributeˡ⁻¹ , [ i₁ ∘ π₂ , (i₂ ∘ zip₂⁻¹) ∘ zip ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈⟨ []-cong₂ ((∘-resp-≈ˡ (sym identityˡ)) ○ pullʳ distributeˡ⁻¹-π₂ ○ identityˡ) refl ⟩∘⟨refl ⟩
[ π₂ , [ i₁ ∘ π₂ , (i₂ ∘ zip₂⁻¹) ∘ zip ] ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
≈˘⟨ []-cong₂ refl (∘-resp-≈ˡ ([]-cong₂ refl (pushʳ (pullˡ project₂)))) ⟩∘⟨refl ⟩
[ π₂ , (π₂ +₁ π₂ ∘ zip⁻¹ ∘ zip) ∘ distributeˡ⁻¹ ] ∘ distributeʳ⁻¹ ∘ (out ⁂ out)
∎
zip∘zip⁻¹ : ∀ {X Y} → zip{X}{Y} ∘ zip⁻¹{X}{Y} ≈ id
zip∘zip⁻¹ = trans (sym (Coit.coit-unique out (zip ∘ zip⁻¹) zip∘zip⁻¹-rec)) Coit.coit-refl
where
zip∘zip⁻¹-rec =
begin
out ∘ zip ∘ zip⁻¹
≈⟨ pullˡ (Coit.coit-commutes (distr ∘ (out ⁂ out))) ⟩
((id +₁ zip) ∘ distr ∘ (out ⁂ out)) ∘ zip⁻¹
≈⟨ pullʳ (pullʳ ⁂∘⟨⟩) ⟩
(id +₁ zip) ∘ distr ∘ ⟨ out ∘ zip₁⁻¹ , out ∘ zip₂⁻¹ ⟩
≈⟨ refl⟩∘⟨ refl⟩∘⟨ ⟨⟩-cong₂ (extend-commutes _) (extend-commutes _) ⟩
(id +₁ zip) ∘ distr ∘ ⟨ [ out ∘ [ now ∘ π₁ , out⁻¹ ∘ (π₁ +₁ π₁) ] , i₂ ∘ zip₁⁻¹ ] ∘ out , [ out ∘ [ now ∘ π₂ , out⁻¹ ∘ [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ∘ out ⟩
≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ ⟨⟩∘ ⟩
(id +₁ zip) ∘ distr ∘ ⟨ [ out ∘ [ now ∘ π₁ , out⁻¹ ∘ (π₁ +₁ π₁) ] , i₂ ∘ zip₁⁻¹ ] , [ out ∘ [ now ∘ π₂ , out⁻¹ ∘ [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ⟩ ∘ out
≈⟨ refl⟩∘⟨ refl⟩∘⟨ ⟨⟩-cong₂ ([]-cong₂ (∘[] ○ []-cong₂ (pullˡ unitlaw) (cancelˡ out∘out⁻¹)) refl) ([]-cong₂ (∘[] ○ []-cong₂ (pullˡ unitlaw) (cancelˡ out∘out⁻¹)) refl) ⟩∘⟨refl ⟩
(id +₁ zip) ∘ distr ∘ ⟨ [ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , i₂ ∘ zip₁⁻¹ ] , [ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ⟩ ∘ out
≈˘⟨ refl⟩∘⟨ pushˡ ([]-unique (zip∘zip⁻¹-rec' ○ sym identityʳ) (pullʳ ⟨⟩∘ ○ ∘-resp-≈ʳ (⟨⟩-cong₂ inject₂ inject₂) ○ pushʳ (sym ⁂∘⟨⟩) ○ ∘-resp-≈ˡ distr-i₂+i₂)) ⟩
(id +₁ zip) ∘ (id +₁ zip⁻¹) ∘ out
≈⟨ pullˡ (+₁∘+₁ ○ +₁-cong₂ identityˡ refl) ⟩
(id +₁ zip ∘ zip⁻¹) ∘ out
∎
where
zip∘zip⁻¹-rec' =
begin
(distr ∘ ⟨ [ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , i₂ ∘ zip₁⁻¹ ] , [ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ⟩) ∘ i₁ ≈⟨ pullʳ ⟨⟩∘ ⟩
distr ∘ ⟨ [ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , i₂ ∘ zip₁⁻¹ ] ∘ i₁ , [ [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] , i₂ ∘ zip₂⁻¹ ] ∘ i₁ ⟩ ≈⟨ refl⟩∘⟨ ⟨⟩-cong₂ inject₁ inject₁ ⟩
distr ∘ ⟨ [ i₁ ∘ π₁ , π₁ +₁ π₁ ] , [ i₁ ∘ π₂ , [ i₂ ∘ π₂ , i₁ ∘ π₂ ] ] ⟩ ≈⟨ distr-helper ⟩
i₁
∎
zip-iso : ∀ X Y → IsIso (zip {X}{Y})
zip-iso X Y .Mor.IsIso.inv = zip⁻¹
zip-iso X Y .Mor.IsIso.iso .Mor.Iso.isoˡ = zip⁻¹∘zip {X = X}{Y = Y}
zip-iso X Y .Mor.IsIso.iso .Mor.Iso.isoʳ = zip∘zip⁻¹ {X = X}{Y = Y}
product-retract : ∀ X Y → Retract (D₀ (X × Y)) (D₀ X × D₀ Y)
product-retract X Y .Mor.Retract.section = ⟨ D₁ π₁ , D₁ π₂ ⟩
product-retract X Y .Mor.Retract.retract = extend [ now , [ τ , σ ] ] ∘ zip
product-retract X Y .Mor.Retract.is-retract = assoc ○
(begin
extend [ now , [ τ , σ ] ] ∘ zip ∘ ⟨ D₁ π₁ , D₁ π₂ ⟩
≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⟨⟩∘ ○ ⟨⟩-cong₂ (extend∘F₁' kleisli _ _ ○ extend-≈ inject₁) (extend∘F₁' kleisli _ _ ○ extend-≈ inject₁) ) ⟨
extend [ now , [ τ , σ ] ] ∘ zip ∘ zip⁻¹ ∘ D₁ i₁
≈⟨ refl⟩∘⟨ pullˡ zip∘zip⁻¹ ○ ∘-resp-≈ʳ identityˡ ⟩
extend [ now , [ τ , σ ] ] ∘ D₁ i₁
≈⟨ extend∘F₁' kleisli _ _ ⟩
extend ([ now , [ τ , σ ] ] ∘ i₁)
≈⟨ extend-≈ inject₁ ○ DK.identityˡ ⟩
id
∎)