{-# OPTIONS --lossy-unification #-}

open import Categories.Category.Core
open import Categories.Category.Distributive
open import Categories.Category.Restriction
open import Categories.Object.Terminal
open import Relation.Binary.Bundles using (Poset)
open import Monad.Helper
open import Data.Product using (_,_)
open import Algebra.Elgot
open import Category.Construction.ElgotAlgebras
open import Categories.FreeObjects.Free
open import Categories.Object.NaturalNumbers
open import Categories.Object.NaturalNumbers.Parametrized
open import Categories.Category.Construction.F-Algebras

import Categories.Morphism as M
import Categories.Morphism.Reasoning as MR
import Categories.Morphism.Properties as MP

import Monad.Instance.K as MIK

module Monad.Instance.K.Kleene {o  e} {C : Category o  e} (distributive : Distributive C) (MK : MIK.MonadK distributive) where
  open import Category.Distributive.Helper distributive
  open Bundles
  
  open MIK distributive
  open Terminal terminal using (!; !-unique; !-unique₂; )
  open MonadK MK
  open Category C
  open Equiv
  open HomReasoning
  open M C
  open MR C
  open MP C
  open kleisliK using (extend; extend-≈)
  open monadK using (μ)
  open import Monad.Instance.K.Strong distributive MK
  open import Monad.Instance.K.Commutative distributive MK
  open import Monad.Instance.K.EquationalLifting distributive MK
  open import Monad.Instance.K.Restriction distributive MK
  open import Monad.Instance.K.OrderEnriched distributive MK
  open Restriction KRestriction renaming (_↓ to _↓'; ↓-denestʳ to ↓-denestʳ'; ↓-cong to ↓-cong'; pidʳ to pidʳ'; ↓-comm to ↓-comm'; ↓-skew-comm to ↓-skew-comm')
  open import Categories.Category.Restriction.Properties.Poset KRestriction
  open import Categories.Category.Restriction.Properties KRestriction renaming (↓-idempotent to ↓-idempotent')
  open import Categories.Object.NaturalNumbers.Parametrized.Properties.F-Algebras C cartesian coproducts
  open import Categories.Monad.Commutative.Properties

  open CommutativeProperties braided KCommutativeMonad


  module BoundedIteration (PNNO : ParametrizedNNO C cartesian) where
    private
      module pnno = ParametrizedNNO PNNO
      module nno = NNO (PNNO⇒NNO C cartesian PNNO)
    open pnno using (universal; z; s; N)
    open nno using () renaming (universal to nno-universal)
    -- open MonadK MK
    open monadK using (η; μ)
    open kleisliK using (extend)

    nno-iso : N   + N
    nno-iso = Lambek.lambek (PNNO⇒Initial₁ PNNO)

    pnno-iso :  {X}  X × N  X + X × N
    pnno-iso {X} = Lambek.lambek (record {  = PNNO-Algebra X N z s ; ⊥-is-initial = PNNO⇒Initial₂ PNNO X })

    1+n : N   + N
    1+n = M._≅_.from nno-iso

    N-out : N   + N
    N-out = nno.universal i₁ (i₂  [ z , s ])

    coherence : 1+n  N-out
    coherence = nno.unique IB IS
      where
      IB : i₁  1+n  z
      IB = begin 
        i₁ ≈˘⟨ identityʳ   
        i₁  id ≈˘⟨ inject₁  
        (id +₁ _)  i₁ ≈⟨ nno.z-commute  
        1+n  z 
      IS : (i₂  [ z , s ])  1+n  1+n  s
      IS = begin 
        (i₂  [ z , s ])  1+n ≈˘⟨ inject₂ ⟩∘⟨refl  
        ((id +₁ [ z , s ])  i₂)  1+n ≈⟨ nno.s-commute  
        1+n  s 

    N-out-zero : N-out  z  i₁
    N-out-zero = sym nno.z-commute

    N-out-succ : N-out  s  i₂
    N-out-succ = begin 
      N-out  s ≈˘⟨ nno.s-commute  
      (i₂  [ z , s ])  N-out ≈⟨ cancelʳ (∘-resp-≈ʳ (sym coherence)  _≅_.isoˡ nno-iso)  
      i₂ 
    
    _#⟩ :  {X A : Obj}  (X  K.₀ A + X)  X × N  K.₀ A
    _#⟩ {X} {A} f = [ id , bot ]  f  universal id ([ π₁ , π₂ ]  distributeˡ⁻¹   id , f )

    PNNO-jointly-epic :  {X Y} {f g : X × N  Y}  (f   id , z  !   g   id , z  ! )  (f  (id  s)  g  (id  s))  f  g
    PNNO-jointly-epic {X} {Y} {f} {g} IB IS = begin 
      f                                                          ≈⟨ introʳ (M._≅_.isoˡ pnno-iso)  
      f  [  id , z  !  , (id  s) ]  M._≅_.from pnno-iso     ≈⟨ pullˡ ∘[]  
      [ f   id , z  !  , f  (id  s) ]  M._≅_.from pnno-iso ≈⟨ ([]-cong₂ IB IS) ⟩∘⟨refl  
      [ g   id , z  !  , g  (id  s) ]  M._≅_.from pnno-iso ≈˘⟨ pullˡ ∘[]  
      g  [  id , z  !  , (id  s) ]  M._≅_.from pnno-iso     ≈⟨ elimʳ (M._≅_.isoˡ pnno-iso)  
      g                                                          

    kleene₁ :  {X Y} (f : X  K.₀ Y + X)  f #⟩  (f #  π₁)
    kleene₁ {X} {Y} f = begin 
      f #⟩                 ≈⟨ helper₁  
      ((f #  h)  (f #⟩)) ≈⟨ ⇂-cong₂ helper₂ refl  
      (f #  π₁)  (f #⟩)  
      where
      h : X × N  X
      h = universal id ([ π₁ , π₂ ]  distributeˡ⁻¹   id , f )
      helper₁ : f #⟩  (f #  h)
      helper₁ = begin 
        (f #⟩)                                 ≈⟨ sym-assoc  
        ([ id , bot ]  f)  h                 ≈⟨ ⊑∘ˡ single-iter  
        ((f #  h)  (([ id , bot ]  f)  h)) ≈⟨ ⇂-cong₂ refl assoc  
        (((f #)  h)  (f #⟩))                 
        where
        single-iter : ([ id , bot ]  f)  (f #)
        single-iter = begin 
          [ id , bot ]  f                                                         ≈˘⟨ []-cong₂ (extend∘F₁ monadK π₁  η.η _ , id   extend-≈ project₁  kleisliK.identityˡ) (bot-restrict (f #)) ⟩∘⟨refl  
          [ extend π₁  K.₁  η.η _ , id  , extend π₁  τ _   f # , bot  ]  f ≈˘⟨ ([]-cong₂ (∘-resp-≈ʳ equationalLifting) refl) ⟩∘⟨refl  
          [ extend π₁  τ _  Δ , extend π₁  τ _   f # , bot  ]  f            ≈˘⟨ pullˡ ∘[]  
          extend π₁  [ τ _  Δ , τ _   f # , bot  ]  f                        ≈˘⟨ refl⟩∘⟨ pullˡ ∘[]  
          extend π₁  τ _  [ Δ ,  f # , bot  ]  f                              ≈⟨ refl⟩∘⟨ refl⟩∘⟨ ([⟨⟩]≈⟨[]⟩ id id (f #) bot) ⟩∘⟨refl  
          extend π₁  τ _   [ id , f # ] , [ id , bot ]   f                    ≈⟨ refl⟩∘⟨ refl⟩∘⟨ ⟨⟩∘  
          extend π₁  τ _   [ id , f # ]  f , [ id , bot ]  f                 ≈˘⟨ refl⟩∘⟨ (refl⟩∘⟨ (⟨⟩-cong₂ (#-Fixpoint (algebras _)) refl))  
          extend π₁  τ _   f # , [ id , bot ]  f                              
      helper₂ : f #  h  f #  π₁
      helper₂ = begin 
        f #  h                                                                                 ≈˘⟨ pullˡ kleisliK.identityʳ  
        extend (f #)  η.η _  h                                                                ≈⟨ refl⟩∘⟨ pnno.unique (sym IB₁) (sym IS₁)  
        extend (f #)  universal (η.η _) (K.₁ f')                                               ≈˘⟨ refl⟩∘⟨ (pnno.unique (sym (Step.IB₂ f')) (sym (Step.IS₂ f')))  
        extend (f #)  ((η.η X  π₁ +₁ f'  id)  distributeˡ⁻¹  (id  N-out)) #               ≈⟨ extend-preserve (f #) ((η.η _  π₁ +₁ f'  id)  distributeˡ⁻¹  (id  N-out)) 
        ((extend (f #) +₁ id)  (η.η _  π₁ +₁ f'  id)  distributeˡ⁻¹  (id  N-out)) #       ≈⟨ #-resp-≈ (algebras _) (pullˡ (+₁∘+₁  +₁-cong₂ (pullˡ kleisliK.identityʳ) identityˡ)) 
        ((f #  π₁ +₁ f'  id)  distributeˡ⁻¹  (id  N-out)) #                                ≈⟨ #-Uniformity (algebras _) (sym uni-step) 
        ((π₁ +₁ id)  distributeˡ⁻¹  (id  N-out)) #  (f #  id)                              ≈˘⟨ (#-resp-≈ (algebras _) (pullˡ (+₁∘+₁  +₁-cong₂ (cancelˡ monadK.identityʳ) identity²))) ⟩∘⟨refl 
        ((μ.η _ +₁ id)  (η.η _  π₁ +₁ id)  distributeˡ⁻¹  (id  N-out)) #  (f #  id)      ≈˘⟨ pullˡ (μ-preserve _) 
        μ.η _  ((η.η _  π₁ +₁ id)  distributeˡ⁻¹  (id  N-out)) #  (f #  id)              ≈˘⟨ refl⟩∘⟨ (#-resp-≈ (algebras _) (∘-resp-≈ˡ (+₁-cong₂ refl (⟨⟩-unique id-comm id-comm))) ⟩∘⟨refl) 
        μ.η _  ((η.η (K.₀ Y)  π₁ +₁ (id  id))  distributeˡ⁻¹  (id  N-out)) #  (f #  id) ≈⟨ refl⟩∘⟨ ((pnno.unique (sym (Step.IB₂ id)) (sym (Step.IS₂ id))) ⟩∘⟨refl) 
        μ.η Y  universal (η.η (K.₀ Y)) (K.₁ (id {K.₀ Y}))  (f #  id)                         ≈⟨ refl⟩∘⟨ (pnno.unique pnno.commute₁ (∘-resp-≈ˡ (sym K.identity)  pnno.commute₂) ⟩∘⟨refl) 
        μ.η Y  universal (η.η (K.₀ Y)) (id {K.₀ (K.₀ Y)})  (f #  id)                         ≈˘⟨ refl⟩∘⟨ pullˡ (pnno.unique (sym η-IB₁) (sym η-IS₁)) 
        μ.η _  η.η _  π₁  (f #  id)                                                         ≈⟨ cancelˡ monadK.identityʳ 
        π₁ {K.₀ Y} {N}  (f #  id)                                                             ≈⟨ project₁ 
        f #  π₁                                                                                
        where
        f' = [ π₁ , π₂ ]  distributeˡ⁻¹   id , f 
        f'-fixpoint : f #  f #  f'
        f'-fixpoint = begin 
          (f #)                                                                       ≈⟨ #-Fixpoint (algebras _)  
          [ id , f # ]  f                                                            ≈˘⟨ sym-assoc  pullˡ (assoc  sym ([]-unique case-i₁ case-i₂))  
          [ π₁ , f #  π₂ ]  distributeˡ⁻¹   [ id , f # ] , id   f               ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⟨⟩∘  ⟨⟩-cong₂ refl identityˡ)  
          [ π₁ , f #  π₂ ]  distributeˡ⁻¹   [ id , f # ]  f , f                 ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ ⟨⟩-cong₂ (#-Fixpoint (algebras _)) refl  
          [ π₁ , f #  π₂ ]  distributeˡ⁻¹   f # , f                              ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityʳ (elimˡ ([]-unique id-comm-sym id-comm-sym)))  
          [ π₁ , f #  π₂ ]  distributeˡ⁻¹  (f #  (id +₁ id))   id , f          ≈˘⟨ refl⟩∘⟨ (extendʳ (distributeˡ⁻¹-natural (f #) id id))  
          [ π₁ , f #  π₂ ]  ((f #  id) +₁ (f #  id))  distributeˡ⁻¹   id , f  ≈⟨ pullˡ ([]∘+₁  []-cong₂ project₁ (pullʳ (project₂  identityˡ)))  
          [ f #  π₁ , f #  π₂ ]  distributeˡ⁻¹   id , f                         ≈˘⟨ pullˡ ∘[]  
          f #  [ π₁ , π₂ ]  distributeˡ⁻¹   id , f                               
          where
          case-i₁ : ([ π₁ , f #  π₂ ]  distributeˡ⁻¹   [ id , f # ] , id )  i₁  id
          case-i₁ = begin 
            ([ π₁ , f #  π₂ ]  distributeˡ⁻¹   [ id , f # ] , id )  i₁ ≈⟨ pullʳ (pullʳ (⟨⟩∘  ⟨⟩-cong₂ inject₁ id-comm-sym))  
            [ π₁ , f #  π₂ ]  distributeˡ⁻¹   id , i₁  id              ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identity² refl)  
            [ π₁ , f #  π₂ ]  distributeˡ⁻¹  (id  i₁)  Δ                ≈⟨ refl⟩∘⟨ (pullˡ distributeˡ⁻¹-i₁)  
            [ π₁ , f #  π₂ ]  i₁  Δ                                       ≈⟨ pullˡ inject₁  
            π₁  Δ                                                           ≈⟨ project₁  
            id                                                               
          case-i₂ : ([ π₁ , f #  π₂ ]  distributeˡ⁻¹   [ id , f # ] , id )  i₂  f #
          case-i₂ = begin 
            ([ π₁ , f #  π₂ ]  distributeˡ⁻¹   [ id , f # ] , id )  i₂ ≈⟨ pullʳ (pullʳ (⟨⟩∘  ⟨⟩-cong₂ inject₂ id-comm-sym))  
            [ π₁ , f #  π₂ ]  distributeˡ⁻¹   f # , i₂  id             ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl)  
            [ π₁ , f #  π₂ ]  distributeˡ⁻¹  (id  i₂)   f # , id      ≈⟨ refl⟩∘⟨ (pullˡ distributeˡ⁻¹-i₂)  
            [ π₁ , f #  π₂ ]  i₂   f # , id                             ≈⟨ extendʳ inject₂  
            f #  π₂   f # , id                                           ≈⟨ elimʳ project₂  
            f #                                                              

        η-helper :  {Z}  η.η Z  (i₁  η.η _) #
        η-helper = sym (#-Fixpoint (algebras _)  cancelˡ inject₁)

        uni-step : ((π₁ +₁ id)  distributeˡ⁻¹  (id  N-out))  (f #  id)  (id +₁ (f #  id))  (f #  π₁ +₁ f'  id)  distributeˡ⁻¹  (id  N-out)
        uni-step = begin 
          ((π₁ +₁ id)  distributeˡ⁻¹  (id  N-out))  (f #  id)                  ≈⟨ pullʳ (pullʳ (⁂∘⁂  ⁂-cong₂ id-comm-sym id-comm  sym ⁂∘⁂))  
          (π₁ +₁ id)  distributeˡ⁻¹  (f #  id)  (id  N-out)                    ≈˘⟨ refl⟩∘⟨ extendʳ distributeˡ⁻¹-natural-id  
          (π₁ +₁ id)  (f #  id +₁ f #  id)  distributeˡ⁻¹  (id  N-out)        ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ project₁ identityˡ)  
          (f #  π₁ +₁ f #  id)  distributeˡ⁻¹  (id  N-out)                     ≈⟨ (+₁-cong₂ refl (⁂-cong₂ f'-fixpoint refl)) ⟩∘⟨refl  
          (f #  π₁ +₁ f #  f'  id)  distributeˡ⁻¹  (id  N-out)                ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityˡ (⁂∘⁂  ⁂-cong₂ refl identity²))  
          (id +₁ (f #  id))  (f #  π₁ +₁ f'  id)  distributeˡ⁻¹  (id  N-out) 

        η-IB₁ : (η.η _  π₁)   id , z  !   η.η _
        η-IB₁ = cancelʳ project₁
        η-IS₁ : (η.η _  π₁)  (id  s)  id  η.η _  π₁
        η-IS₁ = pullʳ (project₁  identityˡ)  sym identityˡ

        IB₁ : (η.η _  h)   id , z  !   η.η _
        IB₁ = cancelʳ (sym pnno.commute₁)
        IS₁ : (η.η _  h)  (id  s)  (K.₁ f')  η.η _  h
        IS₁ = begin 
          (η.η _  h)  (id  s) ≈⟨ pullʳ (sym pnno.commute₂) 
          η.η _  f'  h         ≈⟨ extendʳ (η.commute f')  
          (K.₁ f')  η.η _  h   

        module Step {Z} (p : Z  Z) where
          q = (η.η Z  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out)
          IB₂ : ((η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out)) #   id , z  !   η.η _
          IB₂ = begin 
            ((η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out)) #   id , z  !  ≈˘⟨ #-Uniformity (algebras _) uni-helper  
            ((i₁  η.η _) #)                                                                                                  ≈˘⟨ η-helper  
            η.η _                                                                                                             
            where
            uni-helper : (id +₁  id , z  ! )  i₁  η.η _  ((η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out))   id , z  ! 
            uni-helper = begin 
              (id +₁  id , z  ! )  i₁  η.η _                                                                             ≈⟨ pullˡ (inject₁  identityʳ)  
              i₁  η.η _                                                                                                      ≈˘⟨ refl⟩∘⟨ elimʳ project₁  
              i₁  η.η _  π₁   id , !                                                                                     ≈˘⟨ pullˡ inject₁  assoc²βε  
              (η.η _  π₁ +₁ p  id)  i₁   id , !                                  ≈˘⟨ refl⟩∘⟨ pullˡ distributeˡ⁻¹-i₁  
              (η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  i₁)   id , !           ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identity² refl)  
              (η.η _  π₁ +₁ p  id)  distributeˡ⁻¹   id , i₁  !                  ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ ⟨⟩-cong₂ refl (pullˡ (sym nno.z-commute))  
              (η.η _  π₁ +₁ p  id)  distributeˡ⁻¹   id , N-out  z  !           ≈˘⟨ pullʳ (pullʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identity² refl))  
              ((η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out))   id , z  !  
          pq-helper : q #  (p  id)  K.₁ p  q #
          pq-helper = begin 
            q #  (p  id)        ≈˘⟨ #-Uniformity (algebras _) uni-helper  
            ((K.₁ p +₁ id)  q) # ≈˘⟨ K-preserve p q  
            K.₁ p  q #           
            where
            uni-helper : (id +₁ (p  id))  (K.₁ p +₁ id)  q  q  (p  id)
            uni-helper = begin 
              (id +₁ (p  id))  (K.₁ p +₁ id)  (η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out) ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityˡ identityʳ)  
              (K.₁ p +₁ (p  id))  (η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out)              ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ refl (⁂∘⁂  ⁂-cong₂ refl identity²))  
              (K.₁ p  η.η _  π₁ +₁ (p  p  id))  distributeˡ⁻¹  (id  N-out)                      ≈˘⟨ (+₁-cong₂ (extendʳ (η.commute p)) refl) ⟩∘⟨refl  
              (η.η _  p  π₁ +₁ (p  p  id))  distributeˡ⁻¹  (id  N-out)                          ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ (pullʳ project₁) (⁂∘⁂  ⁂-cong₂ refl identity²))  
              (η.η _  π₁ +₁ p  id)  (p  id +₁ p  id)  distributeˡ⁻¹  (id  N-out)               ≈⟨ refl⟩∘⟨ (extendʳ (distributeˡ⁻¹-natural p id id  ∘-resp-≈ʳ (⁂-cong₂ refl ([]-unique id-comm-sym id-comm-sym))))  
              (η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (p  id)  (id  N-out)                         ≈˘⟨ pullʳ (pullʳ (⁂∘⁂  ⁂-cong₂ id-comm-sym id-comm  sym ⁂∘⁂))  
              ((η.η _  π₁ +₁ p  id)  distributeˡ⁻¹  (id  N-out))  (p  id)                       
          IS₂ : q #  (id  s) 
               K.₁ p  q #
          IS₂ = begin 
            q #  (id  s)                                                              ≈⟨ (#-Fixpoint (algebras _)) ⟩∘⟨refl  
            ([ id , q # ]  q)  (id  s)                                               ≈⟨ (pullˡ ([]∘+₁  []-cong₂ identityˡ refl)) ⟩∘⟨refl 
            ([ η.η _  π₁ , q #  (p  id) ]  distributeˡ⁻¹  (id  N-out))  (id  s) ≈⟨ (([]-cong₂ refl pq-helper) ⟩∘⟨refl) ⟩∘⟨refl 
            ([ η.η _  π₁ , K.₁ p  q # ]  distributeˡ⁻¹  (id  N-out))  (id  s)    ≈⟨ pullʳ (pullʳ (⁂∘⁂  ⁂-cong₂ identity² N-out-succ)) 
            [ η.η _  π₁ , K.₁ p  q # ]  distributeˡ⁻¹  (id  i₂)                    ≈⟨ refl⟩∘⟨ distributeˡ⁻¹-i₂ 
            [ η.η _  π₁ , K.₁ p  q # ]  i₂                                           ≈⟨ inject₂ 
            K.₁ p  q #                                                                 

    kleene₂ :  {X Y} (f : X  K.₀ Y + X) (g : X  K.₀ Y)  (f #⟩)  (g  π₁)  (f #)  g
    kleene₂ {X} {Y} f g leq = ⊑-trans (⊑-trans (⊑-cong₂ refl u-law ⊑-refl) leq₁) (⊑-trans (⊑-cong₂ refl eq₂ ⊑-refl) leq₂)
      where
        u : X × N  K.₀ N + (X × N)
        u = (η.η _  π₂ +₁ (id  s))  distributeʳ⁻¹  (f  id)
        leq₁ : (extend (f #⟩)  τ (X , N)   id , u #   id , z  !  )  (extend (g  π₁)  τ (X , N)   id , u #   id , z  !  )
        leq₁ = ⊑∘ˡ {f = extend (f #⟩)} {g = extend (g  π₁)} (begin 
          extend (f #⟩)                                                                              ≈⟨ extend-≈ leq  
          extend (extend π₁  τ _   g  π₁ , f #⟩ )                                               ≈⟨ kleisliK.assoc  
          extend π₁  extend (τ _   g  π₁ , f #⟩ )                                               ≈˘⟨ refl⟩∘⟨ (extend∘F₁ monadK (τ (K.₀ Y , Y)  (id  (f #⟩)))  g  π₁ , id   extend-≈ (pullʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ identityʳ)))  
          extend π₁  extend (τ _  (id  (f #⟩)))  K.₁  g  π₁ , id                              ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (sym K.homomorphism  K.F-resp-≈ (⁂∘⟨⟩  ⟨⟩-cong₂ kleisliK.identityʳ identity²))  
          extend π₁  extend (τ _  (id  (f #⟩)))  K.₁ (extend (g  π₁)  id)  K.₁  η.η _ , id  ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ equationalLifting  
          extend π₁  extend (τ _  (id  (f #⟩)))  K.₁ (extend (g  π₁)  id)  τ _  Δ            ≈˘⟨ refl⟩∘⟨ (pullʳ (assoc  extendʳ (τ-comm-id (extend (g  π₁)))))  
          extend π₁  (extend (τ _  (id  (f #⟩)))  τ _  (extend (g  π₁)  id))  Δ              ≈˘⟨ refl⟩∘⟨ (pullˡ (sym (τ-kleisli-assoc _ _)))  
          extend π₁  τ _  (extend (g  π₁)  extend (f #⟩))  Δ                                    ≈⟨ refl⟩∘⟨ refl⟩∘⟨ ⁂∘Δ  
          extend π₁  τ _   extend (g  π₁) , extend (f #⟩)                                       )
        -- leq : f #⟩ ≈ extend π₁ ∘ τ _ ∘ ⟨ g ∘ π₁ , f #⟩ ⟩
        -- Proving u-law:
        -- 1. Show that extend (f #⟩) ∘ τ _ ∘ ⟨ id , u # ∘ ⟨ id , z ∘ ! ⟩ ⟩ ≈ ((extend (f #⟩) ∘ τ +₁ id) ∘ distributeˡ⁻¹ ∘ (id ⁂ u))# ∘ ⟨ id , ⟨ id , z ∘ ! ⟩ ⟩   [[leq₁]]
        -- 2. Show that ((extend (f #⟩) ∘ τ +₁ id) ∘ distributeˡ⁻¹ ∘ (id ⁂ u))# ∘ ⟨ id , ⟨ id , z ∘ ! ⟩ ⟩ ≈ f #                                                   [[eq₁]]
        -- -- 1. Proven by strengthening: show that ((extend (f #⟩) ∘ τ +₁ id) ∘ distributeˡ⁻¹ ∘ (id ⁂ u))# ∘ ⟨ π₁ , ⟨ h , π₂ ⟩ ⟩ ≈ f # ∘ h                       [[strengthened]]
        u-law : f #  extend (f #⟩)  τ _   id , u #   id , z  !  
        u-law = begin 
          f #                                                                                 ≈⟨ u-step₂  
          ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))#   id ,  id , z  !   ≈˘⟨ u-step₁  
          extend (f #⟩)  τ _   id , u #   id , z  !                                   
          where
          u-step₁ : (extend (f #⟩)  τ _   id , u #   id , z  !  )  ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))#   id ,  id , z  !  
          u-step₁ = begin 
            (extend (f #⟩)  τ _   id , u #   id , z  !  )                                ≈˘⟨ refl⟩∘⟨ (refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl))  
            extend (f #⟩)  τ _  (id  u #)   id ,  id , z  !                             ≈⟨ refl⟩∘⟨ (pullˡ (τ-comm u))  
            extend (f #⟩)  ((τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   id ,  id , z  !   ≈⟨ pullˡ (extend-preserve _ _  #-resp-≈ (algebras Y) (pullˡ (+₁∘+₁  +₁-cong₂ refl identity²)))  
            ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))#   id ,  id , z  !    
          u-step₂ : f #  ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))#   id ,  id , z  !  
          u-step₂ = begin 
            f #                                                                                              ≈˘⟨ elimʳ (sym pnno.commute₁)  
            f #  h   id , z  !                                                                          ≈⟨ extendʳ (sym strengthened)  
            ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))#   π₁ ,  h , π₂     id , z  !  ≈⟨ refl⟩∘⟨ (⟨⟩∘  ⟨⟩-cong₂ project₁ (⟨⟩∘  ⟨⟩-cong₂ (sym pnno.commute₁) project₂))  
            ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))#   id ,  id , z  !                
            where
              f' : X  X
              f' = [ π₁ , π₂ ]  distributeˡ⁻¹   id , f 
              h : X × N  X
              h = universal id f'  -- universal id (case f inl π₁ inr π₂)
              h-succ : h  (id  s)  [ π₁ , π₂ ]  distributeˡ⁻¹   h , f  h 
              h-succ = begin 
                h  (id  s)                                   ≈˘⟨ pnno.commute₂  
                ([ π₁ , π₂ ]  distributeˡ⁻¹   id , f )  h ≈⟨ pullʳ (pullʳ (⟨⟩∘  ⟨⟩-cong₂ identityˡ refl))  
                [ π₁ , π₂ ]  distributeˡ⁻¹   h , f  h     
              #⟩-succ : f #⟩  (id  s)  [ id , bot ]  f  f'  h
              #⟩-succ = begin 
                ([ id , bot ]  f  universal id ([ π₁ , π₂ ]  distributeˡ⁻¹   id , f ))  (id  s) ≈⟨ pullʳ (pullʳ (sym pnno.commute₂))  
                [ id , bot ]  f  f'  h 
              strengthened : ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   π₁ ,  h , π₂    f #  h
              strengthened = begin 
                ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   π₁ ,  h , π₂   ≈˘⟨ #-Uniformity (algebras _) (sym uni-helper₁)  
                ((π₂ +₁ π₁)  distributeˡ⁻¹   id  s , f  h ) #                              ≈⟨ #-Uniformity (algebras _) (sym uni-helper₂)  
                f #  h                                                                          
                where
                helper-dual :  {A B D} (w : A  B + D)  (id +₁  id , i₂  π₂ )  distributeˡ⁻¹   id , w   (id +₁  id , w  π₁ )  distributeˡ⁻¹   id , w 
                helper-dual w = begin 
                  (id +₁  id , i₂  π₂ )  distributeˡ⁻¹   id , w                                 ≈˘⟨ (+₁-cong₂ ⁂-η (⟨⟩-cong₂ ⁂-η refl)) ⟩∘⟨refl  
                  ( π₁ , π₂  +₁   π₁ , π₂  , i₂  π₂ )  distributeˡ⁻¹   id , w               ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ (⁂∘⟨⟩  ⟨⟩-cong₂ (project₁  identityˡ) identityˡ) (⟨⟩∘  ⟨⟩-cong₂ (⁂∘⟨⟩  ⟨⟩-cong₂ (project₁  identityˡ) identityˡ) (pullʳ project₁  project₂)))  
                  (π₁  id +₁ p)  ( id  i₁ , π₂  +₁  id  i₂ , π₂ )  distributeˡ⁻¹   id , w  ≈⟨ refl⟩∘⟨ extendʳ dist-step  
                  (π₁  id +₁ p)  distributeˡ⁻¹   id , π₂    id , w                             ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⟨⟩∘  ⟨⟩-cong₂ identityˡ project₂)  
                  (π₁  id +₁ p)  distributeˡ⁻¹    id , w  , w                                   ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⟨⟩∘  ⟨⟩-cong₂ (cancelʳ project₁) ((pullʳ project₂)  identityˡ))  
                  (π₁  id +₁ p)  distributeˡ⁻¹  ( id , w   id)   id , w                       ≈˘⟨ refl⟩∘⟨ (extendʳ distributeˡ⁻¹-natural-id)  
                  (π₁  id +₁ p)  ( id , w   id +₁  id , w   id)  distributeˡ⁻¹   id , w    ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ (⁂∘⁂  (⁂-cong₂ project₁ identity²)  ⟨⟩-unique id-comm id-comm) (⟨⟩∘  ⟨⟩-cong₂ ((⁂∘⁂  ⁂-cong₂ project₁ identity²)  ⟨⟩-unique id-comm id-comm) (pullʳ project₁  pullˡ project₂)))  
                  (id +₁  id , w  π₁ )  distributeˡ⁻¹   id , w                                  
                  where
                  p =  π₁  id , π₂  π₁ 
                  dist-step : ( id  i₁ , π₂  +₁  id  i₂ , π₂ )  distributeˡ⁻¹  distributeˡ⁻¹   id , π₂ 
                  dist-step = Iso⇒Mono (IsIso.iso isIsoˡ) _ _ (begin 
                    distributeˡ  ( id  i₁ , π₂  +₁  id  i₂ , π₂ )  distributeˡ⁻¹ ≈⟨ pullˡ ([]∘+₁  []-cong₂ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl) (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl))  
                    [  id  i₁ , i₁  π₂  ,  id  i₂ , i₂  π₂  ]  distributeˡ⁻¹    ≈⟨ ([⟨⟩]≈⟨[]⟩ _ _ _ _) ⟩∘⟨refl  
                     distributeˡ , (π₂ +₁ π₂)   distributeˡ⁻¹                         ≈⟨ ⟨⟩∘  ⟨⟩-cong₂ (IsIso.isoʳ isIsoˡ) distributeˡ⁻¹-π₂  
                     id , π₂                                                           ≈˘⟨ cancelˡ (IsIso.isoʳ isIsoˡ)  
                    distributeˡ  distributeˡ⁻¹   id , π₂                             )
                helper :  {A B D} (w : A  B + D)  ( id , i₁  π₂  +₁ id)  distributeˡ⁻¹   id , w   ( id , w  π₁  +₁ id)  distributeˡ⁻¹   id , w 
                helper w = begin 
                  ( id , i₁  π₂  +₁ id)  distributeˡ⁻¹   id , w                                 ≈˘⟨ (+₁-cong₂ (⟨⟩-cong₂ ⁂-η refl) ⁂-η) ⟩∘⟨refl  
                  (  π₁ , π₂  , i₁  π₂  +₁  π₁ , π₂ )  distributeˡ⁻¹   id , w               ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ (⟨⟩∘  ⟨⟩-cong₂ (⁂∘⟨⟩  ⟨⟩-cong₂ (project₁  identityˡ) identityˡ) ((pullʳ project₁)  project₂)) (⁂∘⟨⟩  ⟨⟩-cong₂ (project₁  identityˡ) identityˡ)) 
                  (p +₁ π₁  id)  ( id  i₁ , π₂  +₁  id  i₂ , π₂ )  distributeˡ⁻¹   id , w  ≈⟨ refl⟩∘⟨ extendʳ dist-step  
                  (p +₁ π₁  id)  distributeˡ⁻¹   id , π₂    id , w                             ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⟨⟩∘  ⟨⟩-cong₂ identityˡ project₂)  
                  (p +₁ π₁  id)  distributeˡ⁻¹    id , w  , w                                   ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⟨⟩∘  ⟨⟩-cong₂ (cancelʳ project₁) ((pullʳ project₂)  identityˡ))  
                  (p +₁ π₁  id)  distributeˡ⁻¹  ( id , w   id)   id , w                       ≈˘⟨ refl⟩∘⟨ (extendʳ distributeˡ⁻¹-natural-id) 
                  (p +₁ π₁  id)  ( id , w   id +₁  id , w   id)  distributeˡ⁻¹   id , w    ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ (⟨⟩∘  ⟨⟩-cong₂ ((⁂∘⁂  ⁂-cong₂ project₁ identity²)  ⟨⟩-unique id-comm id-comm) (pullʳ project₁  pullˡ project₂)) ((⁂∘⁂  ⁂-cong₂ project₁ identity²)  ⟨⟩-unique id-comm id-comm))  
                  ( id , w  π₁  +₁ id)  distributeˡ⁻¹   id , w                                  
                  where
                  p =  π₁  id , π₂  π₁ 
                  dist-step : ( id  i₁ , π₂  +₁  id  i₂ , π₂ )  distributeˡ⁻¹  distributeˡ⁻¹   id , π₂ 
                  dist-step = Iso⇒Mono (IsIso.iso isIsoˡ) _ _ (begin 
                    distributeˡ  ( id  i₁ , π₂  +₁  id  i₂ , π₂ )  distributeˡ⁻¹ ≈⟨ pullˡ ([]∘+₁  []-cong₂ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl) (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl))  
                    [  id  i₁ , i₁  π₂  ,  id  i₂ , i₂  π₂  ]  distributeˡ⁻¹    ≈⟨ ([⟨⟩]≈⟨[]⟩ _ _ _ _) ⟩∘⟨refl  
                     distributeˡ , (π₂ +₁ π₂)   distributeˡ⁻¹                         ≈⟨ ⟨⟩∘  ⟨⟩-cong₂ (IsIso.isoʳ isIsoˡ) distributeˡ⁻¹-π₂  
                     id , π₂                                                           ≈˘⟨ cancelˡ (IsIso.isoʳ isIsoˡ)  
                    distributeˡ  distributeˡ⁻¹   id , π₂                             )
                uni-helper₁ : ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))   π₁ ,  h , π₂    (id +₁  π₁ ,  h , π₂  )  (π₂ +₁ π₁)  distributeˡ⁻¹   id  s , f  h 
                uni-helper₁ = begin 
                  ((extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  u))   π₁ ,  h , π₂                                                                                   ≈⟨ pullʳ (pullʳ (∘-resp-≈ˡ (⁂-cong₂ (sym identity²) sym-assoc  sym ⁂∘⁂)  pullʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ (⁂∘⟨⟩  ⟨⟩-cong₂ refl identityˡ))))  
                  (extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  (η.η _  π₂ +₁ (id  s))  distributeʳ⁻¹)   π₁ ,  f  h , π₂                                          ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ pullˡ (⁂∘⁂  ⁂-cong₂ identity² refl)  
                  (extend (f #⟩)  τ _ +₁ id)  distributeˡ⁻¹  (id  (η.η _  π₂ +₁ (id  s)))  (id  distributeʳ⁻¹)   π₁ ,  f  h , π₂                                   ≈⟨ refl⟩∘⟨ (extendʳ (sym (distributeˡ⁻¹-natural id (η.η _  π₂) (id  s))))  
                  (extend (f #⟩)  τ _ +₁ id)  (id  (η.η _  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  distributeʳ⁻¹)   π₁ ,  f  h , π₂                              ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ assoc identityˡ)  
                  (extend (f #⟩)  τ _  (id  (η.η _  π₂)) +₁ id  (id  s))  distributeˡ⁻¹  (id  distributeʳ⁻¹)   π₁ ,  f  h , π₂                                    ≈˘⟨ (+₁-cong₂ (∘-resp-≈ʳ (∘-resp-≈ʳ (⁂∘⁂  ⁂-cong₂ identity² refl))) refl) ⟩∘⟨refl  
                  (extend (f #⟩)  τ _  (id  (η.η _))  (id  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  distributeʳ⁻¹)   π₁ ,  f  h , π₂                             ≈⟨ (+₁-cong₂ (∘-resp-≈ʳ (pullˡ (τ-η _))) refl) ⟩∘⟨refl  
                  (extend (f #⟩)  η.η _  (id  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  distributeʳ⁻¹)   π₁ ,  f  h , π₂                                            ≈⟨ (+₁-cong₂ (pullˡ kleisliK.identityʳ) refl) ⟩∘⟨refl  
                  (f #⟩  (id  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  distributeʳ⁻¹)   π₁ ,  f  h , π₂                                                             ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂-cong₂ refl (elimʳ swap∘swap)) ⟩∘⟨refl  
                  (f #⟩  (id  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  distributeʳ⁻¹  swap  swap)   π₁ ,  f  h , π₂                                               ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂-cong₂ refl (extendʳ distributeʳ⁻¹∘swap)) ⟩∘⟨refl  
                  (f #⟩  (id  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  (swap +₁ swap)  distributeˡ⁻¹  swap)   π₁ ,  f  h , π₂                                     ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ pullˡ (⁂∘⁂  ⁂-cong₂ identity² refl)  
                  (f #⟩  (id  π₂) +₁ id  (id  s))  distributeˡ⁻¹  (id  (swap +₁ swap))  (id  distributeˡ⁻¹  swap)   π₁ ,  f  h , π₂                              ≈⟨ ∘-resp-≈ʳ (extendʳ (sym (distributeˡ⁻¹-natural _ _ _)))  pullˡ +₁∘+₁  
                  ((f #⟩  (id  π₂))  (id  swap) +₁ (id  (id  s))  (id  swap))  distributeˡ⁻¹  (id  distributeˡ⁻¹  swap)   π₁ ,  f  h , π₂                      ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ pullˡ (⁂∘⁂  ⁂-cong₂ identity² refl)  
                  ((f #⟩  (id  π₂))  (id  swap) +₁ (id  (id  s))  (id  swap))  distributeˡ⁻¹  (id  distributeˡ⁻¹)  (id  swap)   π₁ ,  f  h , π₂               ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ swap∘⟨⟩)  
                  ((f #⟩  (id  π₂))  (id  swap) +₁ (id  (id  s))  (id  swap))  distributeˡ⁻¹  (id  distributeˡ⁻¹)   π₁ ,  π₂ , f  h                             ≈⟨ (+₁-cong₂ (pullʳ (⁂∘⁂  ⁂-cong₂ identity² project₂)) (⁂∘⁂  ⁂-cong₂ identity² (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl))) ⟩∘⟨refl  
                  (f #⟩  (id  π₁) +₁ (id   π₂ , s  π₁ ))  distributeˡ⁻¹  (id  distributeˡ⁻¹)   π₁ ,  π₂ , f  h                                                    ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ cancelˡ (_≅_.isoˡ ×-assoc)  
                  (f #⟩  (id  π₁) +₁ (id   π₂ , s  π₁ ))  distributeˡ⁻¹  (id  distributeˡ⁻¹)  _≅_.to ×-assoc  _≅_.from ×-assoc   π₁ ,  π₂ , f  h                ≈⟨ refl⟩∘⟨ (sym-assoc  extendʳ (assoc  distributeˡ⁻¹-assoc))  
                  (f #⟩  (id  π₁) +₁ (id   π₂ , s  π₁ ))  (_≅_.to ×-assoc +₁ _≅_.to ×-assoc)  distributeˡ⁻¹  _≅_.from ×-assoc   π₁ ,  π₂ , f  h                   ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ (assocʳ∘⟨⟩  ⟨⟩-cong₂ ⁂-η refl)  
                  (f #⟩  (id  π₁) +₁ (id   π₂ , s  π₁ ))  (_≅_.to ×-assoc +₁ _≅_.to ×-assoc)  distributeˡ⁻¹   id , f  h                                              ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ (pullʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ project₁)) (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ (⟨⟩∘  ⟨⟩-cong₂ project₂ (pullʳ project₁))))  
                  (f #⟩   π₁  π₁ , π₂  π₁  +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                                           ≈⟨ (+₁-cong₂ (∘-resp-≈ʳ (sym ⟨⟩∘  elimˡ ⁂-η)) refl) ⟩∘⟨refl  
                  (f #⟩  π₁ +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                                                              ≈⟨ (+₁-cong₂ assoc²βε refl) ⟩∘⟨refl  
                  ([ id , bot ]  f  h  π₁ +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                                              ≈˘⟨ +₁-cong₂ (∘-resp-≈ʳ project₂) refl ⟩∘⟨refl  
                  ([ id , bot ]  π₂   id , f  h  π₁  +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                                ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ assoc identityʳ)  
                  ([ id , bot ]  π₂ +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  ( id , f  h  π₁  +₁ id)  distributeˡ⁻¹   id , f  h                                        ≈⟨ refl⟩∘⟨ (+₁-cong₂ (⟨⟩-cong₂ refl sym-assoc) refl) ⟩∘⟨refl  
                  ([ id , bot ]  π₂ +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  ( id , (f  h)  π₁  +₁ id)  distributeˡ⁻¹   id , f  h                                      ≈˘⟨ refl⟩∘⟨ helper (f  h)  
                  ([ id , bot ]  π₂ +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  ( id , i₁  π₂  +₁ id)  distributeˡ⁻¹   id , f  h                                           ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ ((pullʳ project₂)  cancelˡ inject₁) identityʳ) 
                  (π₂ +₁  π₁  π₁ ,  π₂ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                                                                     ≈⟨ (+₁-cong₂ refl (⟨⟩-cong₂ refl (⟨⟩-cong₂ (sym small-step) refl))) ⟩∘⟨refl 
                  (π₂ +₁  π₁  π₁ ,  [ π₁ , π₂ ]  distributeˡ⁻¹   h  π₁ , i₂  π₂  , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                     ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityʳ (⟨⟩∘  ⟨⟩-cong₂ (pullʳ (cancelʳ project₁)) (⟨⟩∘  ⟨⟩-cong₂ (pullʳ (pullʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identityʳ identityˡ))) (pullʳ (pullʳ (pullʳ project₁  identityʳ))))))  
                  (π₂ +₁  π₁  π₁  π₁ ,  [ π₁ , π₂ ]  distributeˡ⁻¹  (h  π₁  id) , s  π₂  π₁  π₁  )  (id +₁  id , i₂  π₂ )  distributeˡ⁻¹   id , f  h       ≈⟨ refl⟩∘⟨ helper-dual (f  h)  
                  (π₂ +₁  π₁  π₁  π₁ ,  [ π₁ , π₂ ]  distributeˡ⁻¹  (h  π₁  id) , s  π₂  π₁  π₁  )  (id +₁  id , (f  h)  π₁ )  distributeˡ⁻¹   id , f  h  ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityʳ (⟨⟩∘  ⟨⟩-cong₂ (pullʳ (pullʳ project₁  identityʳ)) (⟨⟩∘  ⟨⟩-cong₂ (pullʳ (pullʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identityʳ identityˡ))  sym (pullʳ (pullʳ ⟨⟩∘))) (pullʳ (pullʳ (pullʳ project₁  identityʳ))))))  
                  (π₂ +₁  π₁  π₁ ,  ([ π₁ , π₂ ]  distributeˡ⁻¹   h , f  h )  π₁ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                     ≈˘⟨ (+₁-cong₂ refl (⟨⟩-cong₂ refl (⟨⟩-cong₂ (pullˡ ((sym pnno.commute₂)  assoc²βε  ∘-resp-≈ʳ (∘-resp-≈ʳ (⟨⟩∘  ⟨⟩-cong₂ identityˡ refl)))) refl))) ⟩∘⟨refl  
                  (π₂ +₁  π₁  π₁ ,  h  (id  s)  π₁ , s  π₂  π₁  )  distributeˡ⁻¹   id , f  h                                                                      ≈˘⟨ (+₁-cong₂ refl (⟨⟩∘  ⟨⟩-cong₂ refl (⟨⟩∘  ⟨⟩-cong₂ assoc assoc))) ⟩∘⟨refl 
                  (π₂ +₁  π₁ ,  h  (id  s) , s  π₂    π₁)  distributeˡ⁻¹   id , f  h                                                                                ≈˘⟨ (+₁-cong₂ refl (pullˡ (⟨⟩∘  ⟨⟩-cong₂ (project₁  identityˡ) (⟨⟩∘  ⟨⟩-cong₂ refl project₂)))) ⟩∘⟨refl 
                  (π₂ +₁  π₁ ,  h , π₂    (id  s)  π₁)  distributeˡ⁻¹   id , f  h                                                                                    ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ (project₂  identityˡ) (pullʳ project₁)) 
                  (π₂ +₁  π₁ ,  h , π₂    π₁)  ((id  s)  id +₁ (id  s)  id)  distributeˡ⁻¹   id , f  h                                                            ≈⟨ refl⟩∘⟨ (extendʳ (distributeˡ⁻¹-natural (id  s) id id)) 
                  (π₂ +₁  π₁ ,  h , π₂    π₁)  distributeˡ⁻¹  ((id  s)  (id +₁ id))   id , f  h                                                                     ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityʳ (elimˡ ([]-unique id-comm-sym id-comm-sym))) 
                  (π₂ +₁  π₁ ,  h , π₂    π₁)  distributeˡ⁻¹   id  s , f  h                                                                                           ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityˡ refl) 
                  (id +₁  π₁ ,  h , π₂  )  (π₂ +₁ π₁)  distributeˡ⁻¹   id  s , f  h                                                                                   
                  where
                    small-step : [ π₁ , π₂ ]  distributeˡ⁻¹   h  π₁ , i₂  π₂   π₂
                    small-step = begin 
                      [ π₁ , π₂ ]  distributeˡ⁻¹   h  π₁ , i₂  π₂         ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl)  
                      [ π₁ , π₂ ]  distributeˡ⁻¹  (id  i₂)   h  π₁ , π₂  ≈⟨ refl⟩∘⟨ (pullˡ distributeˡ⁻¹-i₂)  
                      [ π₁ , π₂ ]  i₂   h  π₁ , π₂                         ≈⟨ pullˡ inject₂  
                      π₂   h  π₁ , π₂                                       ≈⟨ project₂  
                      π₂                                                        
                uni-helper₂ : f  h  (id +₁ h)  (π₂ +₁ π₁)  distributeˡ⁻¹   id  s , f  h 
                uni-helper₂ = sym (begin 
                  (id +₁ h)  (π₂ +₁ π₁)  distributeˡ⁻¹   id  s , f  h                                                                    ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityʳ identityˡ)  
                  (id +₁ h)  (π₂ +₁ π₁)  distributeˡ⁻¹  ((id  s)  id)   id , f  h                                                      ≈⟨ refl⟩∘⟨ refl⟩∘⟨ extendʳ (sym distributeˡ⁻¹-natural-id) 
                  (id +₁ h)  (π₂ +₁ π₁)  ((id  s)  id +₁ (id  s)  id)  distributeˡ⁻¹   id , f  h                                     ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityˡ refl)  pullˡ (+₁∘+₁  +₁-cong₂ (project₂  identityˡ) (pullʳ project₁)) 
                  (π₂ +₁ h  (id  s)  π₁)  distributeˡ⁻¹   id , f  h                                                                     ≈⟨ (+₁-cong₂ refl ((pullˡ h-succ)  assoc²βε)) ⟩∘⟨refl  
                  (π₂ +₁ [ π₁ , π₂ ]  distributeˡ⁻¹   h , f  h   π₁)  distributeˡ⁻¹   id , f  h                                      ≈˘⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityʳ (pullʳ (pullʳ ((⟨⟩∘  ⟨⟩-cong₂ (pullʳ (cancelʳ project₁)) project₂)  sym ⟨⟩∘))))  
                  (π₂ +₁ [ π₁ , π₂ ]  distributeˡ⁻¹   h  π₁  π₁ , π₂ )  ((id +₁  id , (f  h)  π₁ ))  distributeˡ⁻¹   id , f  h  ≈˘⟨ refl⟩∘⟨ helper-dual (f  h)  
                  (π₂ +₁ [ π₁ , π₂ ]  distributeˡ⁻¹   h  π₁  π₁ , π₂ )  (id +₁  id , i₂  π₂ )  distributeˡ⁻¹   id , f  h         ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ identityʳ (pullʳ (pullʳ (⟨⟩∘  ⟨⟩-cong₂ (pullʳ (cancelʳ project₁)) project₂))))  
                  (π₂ +₁ [ π₁ , π₂ ]  distributeˡ⁻¹   h  π₁ , i₂  π₂ )  distributeˡ⁻¹   id , f  h                                    ≈˘⟨ (+₁-cong₂ refl (∘-resp-≈ʳ (∘-resp-≈ʳ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl)))) ⟩∘⟨refl  
                  (π₂ +₁ [ π₁ , π₂ ]  distributeˡ⁻¹  (id  i₂)   h  π₁ , π₂ )  distributeˡ⁻¹   id , f  h                             ≈⟨ (+₁-cong₂ refl (∘-resp-≈ʳ (pullˡ distributeˡ⁻¹-i₂))) ⟩∘⟨refl  
                  (π₂ +₁ [ π₁ , π₂ ]  i₂   h  π₁ , π₂ )  distributeˡ⁻¹   id , f  h                                                    ≈⟨ (+₁-cong₂ refl (pullˡ inject₂  project₂)) ⟩∘⟨refl   
                  (π₂ +₁ π₂)  distributeˡ⁻¹   id , f  h                                                                                    ≈⟨ pullˡ distributeˡ⁻¹-π₂  project₂  
                  f  h                                                                                                                         ) 
        eq₂ : (extend (g  π₁)  τ _   id , u #   id , z  !  )  (g  (u #   id , z  ! ))
        eq₂ = begin 
          extend (g  π₁)  τ _   id , u #   id , z  !                                             ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identity² refl)  
          extend (g  π₁)  τ _  (id  u #)   id ,  id , z  !                                      ≈⟨ refl⟩∘⟨ (pullˡ (τ-comm u))  
          extend (g  π₁)  ((τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   id ,  id , z  !            ≈⟨ pullˡ ((extend-preserve _ _)  #-resp-≈ (algebras Y) (pullˡ (+₁∘+₁  +₁-cong₂ refl identity²)))  
          ((extend (g  π₁)  τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   id ,  id , z  !            ≈˘⟨ (#-resp-≈ (algebras Y) (∘-resp-≈ˡ (+₁-cong₂ (pullˡ (extend∘F₁ monadK _ _  extend-≈ project₁)) refl))) ⟩∘⟨refl 
          ((extend π₁  K.₁ (g  id)  τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   id ,  id , z  !   ≈˘⟨ #-resp-≈ (algebras Y) (∘-resp-≈ˡ (+₁-cong₂ (∘-resp-≈ʳ (τ-comm-id g)) refl)) ⟩∘⟨refl 
          ((extend π₁  τ _  (g  id) +₁ id)  distributeˡ⁻¹  (id  u)) #   id ,  id , z  !       ≈˘⟨ pullˡ (sym (#-Uniformity (algebras Y) (sym by-uni)))  
          ((extend π₁  τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #  (g  id)   id ,  id , z  !       ≈⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityʳ identityˡ)  
          ((extend π₁  τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   g ,  id , z  !                   ≈˘⟨ pullˡ ((extend-preserve _ _)  #-resp-≈ (algebras Y) (pullˡ (+₁∘+₁  +₁-cong₂ refl identity²)))  
          extend π₁  ((τ _ +₁ id)  distributeˡ⁻¹  (id  u)) #   g ,  id , z  !                   ≈˘⟨ refl⟩∘⟨ (pullˡ (τ-comm u))  
          extend π₁  τ _  (id  u #)   g ,  id , z  !                                             ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (⁂∘⟨⟩  ⟨⟩-cong₂ identityˡ refl)  
          extend π₁  τ _   g , u #   id , z  !                                                    
          where
          by-uni : ((extend π₁  τ _ +₁ id)  distributeˡ⁻¹  (id  u))  (g  id)  (id +₁ g  id)  (extend π₁  τ _  (g  id) +₁ id)  distributeˡ⁻¹  (id  u)
          by-uni = begin 
            ((extend π₁  τ _ +₁ id)  distributeˡ⁻¹  (id  u))  (g  id)                ≈⟨ pullʳ (pullʳ ((⁂∘⁂  ⁂-cong₂ id-comm-sym id-comm)  sym ⁂∘⁂))  
            (extend π₁  τ _ +₁ id)  distributeˡ⁻¹  (g  id)  (id  u)                  ≈˘⟨ refl⟩∘⟨ (extendʳ distributeˡ⁻¹-natural-id)  
            (extend π₁  τ _ +₁ id)  (g  id +₁ g  id)  distributeˡ⁻¹  (id  u)        ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ assoc id-comm-sym)  sym (pullˡ (+₁∘+₁  +₁-cong₂ identityˡ refl))  
            (id +₁ g  id)  (extend π₁  τ _  (g  id) +₁ id)  distributeˡ⁻¹  (id  u) 
        leq₂ : (g  (u #   id , z  ! ))  g
        leq₂ = begin 
          (g  ((u #)   id , z  ! ))       ≈⟨ ⇂-cong₂ ⊑-refl refl  
          ((g  g)  ((u #)   id , z  ! )) ≈⟨ ⇂-assoc  
          (g  (g  ((u #)   id , z  ! )))