open import Cat.Monoidal.Instances.Cartesian
open import Cat.Monoidal.Diagram.Monoid
open import Cat.Diagram.Product.Solver
open import Cat.Diagram.Terminal
open import Cat.Diagram.Comonad
open import Cat.Diagram.Product
open import Cat.Diagram.Monad
open import Cat.Prelude

import Cat.Reasoning as Cat

open Comonad-on
open Monad-on
open Functor
open _=>_
module Cat.Diagram.Comonad.Writer where

Writer (co)monadsπŸ”—

If is an object in a Cartesian monoidal category then the functor β€œproduct with ” functor, can naturally be equipped with the structure of a comonad. This structure embodies a particular view of as a resource, which in particular can be freely dropped and duplicated. Dropping is necessary to form the counit map and duplicating becomes the comultiplication

module _ {o β„“} (C : Precategory o β„“) (A : ⌞ C ⌟) (prod : βˆ€ B β†’ Product C A B) where
  open Cat C

  private module _ {B} where open Product (prod B) using (⟨_,_⟩ ; π₁ ; Ο€β‚‚ ; Ο€β‚βˆ˜βŸ¨βŸ© ; Ο€β‚‚βˆ˜βŸ¨βŸ© ; ⟨⟩∘ ; unique ; uniqueβ‚‚) public
  private module _ B where open Product (prod B) renaming (apex to AΓ—) using () public

To functional programmers, the functor is of particular importance when is equipped with a monoid structure, in which case we can make into a monad: the Writer monad with values in We will keep with this name even in the comonadic setting.

  Writer : Functor C C
  Writer .Fβ‚€   = AΓ—
  Writer .F₁ f = ⟨ π₁ , f ∘ Ο€β‚‚ ⟩
  Writer .F-id = sym (unique (idr _) id-comm)
  Writer .F-∘ f g = sym (unique (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ extendr Ο€β‚‚βˆ˜βŸ¨βŸ©))

Since we’ve already decided that the comonad structure is built on dropping and duplicating, our structure maps are essentially forced on us:

  Writer-comonad : Comonad-on Writer
  Writer-comonad .counit .Ξ· x = Ο€β‚‚
  Writer-comonad .comult .Ξ· x = ⟨ π₁ , id ⟩
The proof that these maps equip with a comonad structure are routine reasoning about products, and so we will leave them in this <details> block for the curious reader.
  Writer-comonad .counit .is-natural x y f = Ο€β‚‚βˆ˜βŸ¨βŸ©
  Writer-comonad .comult .is-natural x y f = uniqueβ‚‚
    (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ idl _)
    (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ cancelr Ο€β‚‚βˆ˜βŸ¨βŸ©)
  Writer-comonad .Ξ΄-idl = uniqueβ‚‚
    (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ cancelr Ο€β‚‚βˆ˜βŸ¨βŸ©)
    (idr _) (idr _)
  Writer-comonad .Ξ΄-idr = Ο€β‚‚βˆ˜βŸ¨βŸ©
  Writer-comonad .Ξ΄-assoc = ⟨⟩∘ _ βˆ™ apβ‚‚ ⟨_,_⟩ refl (pullr Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ id-comm) βˆ™ sym (⟨⟩∘ _)

Writer monadsπŸ”—

We will now prove that the construction of Writer as a monad, familiar from functional programming, works in the generality of letting be an arbitrary Cartesian monoidal category, and with equipped with an arbitrary monoid structure.

module _ {o β„“} (C : Precategory o β„“) (prods : βˆ€ A B β†’ Product C A B) (term : Terminal C) (A : ⌞ C ⌟) where
  open Binary-products C prods
  open Terminal term
  open Cat C

The key take-away is that the usual definition works: at the level of generalised elements, the unit of the monad maps to where is the unit of the monoid; similarly, the multiplication sends to where we write the monoid’s multiplication by juxtaposition.

  monoid→writer-monad
    : Monoid-on (Cartesian-monoidal prods term) A β†’ Monad-on (Writer C A (prods A))
  monoid→writer-monad monoid = mk where
    module m = Monoid-on monoid

    mk : Monad-on _
    mk .unit .η x = ⟨ m.η ∘ ! , id ⟩
    mk .mult .Ξ· x = ⟨ m.ΞΌ ∘ ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ , Ο€β‚‚ ∘ Ο€β‚‚ ⟩

Above, we have written these structure maps in point-free style. The proof strategy for showing that these obey the monad laws is noting that this can be shown componentwise. On the β€œ component” of the pair, we have a monoid law; and the right component is preserved. Implementing this is, again, mostly an exercise in dealing with products.

    mk .unit .is-natural x y f = ⟨⟩-uniqueβ‚‚ (pulll Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ idl f)
      (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ sym (pullr (sym (!-unique _))))
      (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ idr f)
    mk .mult .is-natural x y f = products! prods
    mk .ΞΌ-unitr =
      let
        lemma =
          m.ΞΌ ∘ ⟨ π₁ , m.Ξ· ∘ ! ∘ Ο€β‚‚ ⟩               β‰‘Λ˜βŸ¨ apβ‚‚ _∘_ refl (⟨⟩-unique (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ idl π₁) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ apβ‚‚ _∘_ refl (!-unique _))) ⟩
          m.ΞΌ ∘ ⟨ id ∘ π₁ , m.Ξ· ∘ Ο€β‚‚ ⟩ ∘ ⟨ π₁ , ! ⟩ β‰‘βŸ¨ pulll m.ΞΌ-unitr ⟩
          π₁ ∘ ⟨ π₁ , ! ⟩                           β‰‘βŸ¨ Ο€β‚βˆ˜βŸ¨βŸ© ⟩
          π₁                                        ∎
      in ⟨⟩-uniqueβ‚‚ (products! prods βˆ™ lemma) (products! prods) (idr π₁) (idr Ο€β‚‚)
    mk .ΞΌ-unitl =
      let
        lemma =
          m.ΞΌ ∘ ⟨ m.Ξ· ∘ ! , π₁ ⟩                    β‰‘Λ˜βŸ¨ apβ‚‚ _∘_ refl (⟨⟩-unique (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ idl π₁)) ⟩
          m.ΞΌ ∘ ⟨ m.Ξ· ∘ π₁ , id ∘ Ο€β‚‚ ⟩ ∘ ⟨ ! , π₁ ⟩ β‰‘βŸ¨ pulll m.ΞΌ-unitl ⟩
          Ο€β‚‚ ∘ ⟨ ! , π₁ ⟩                           β‰‘βŸ¨ Ο€β‚‚βˆ˜βŸ¨βŸ© ⟩
          π₁                                        ∎
      in ⟨⟩-uniqueβ‚‚ (products! prods βˆ™ lemma) (products! prods) (idr π₁) (idr Ο€β‚‚)
    mk .ΞΌ-assoc {x} =
      let
        lemma =
          π₁ ∘ ⟨ m.ΞΌ ∘ ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ , Ο€β‚‚ ∘ Ο€β‚‚ ⟩ ∘ ⟨ π₁ , ⟨ m.ΞΌ ∘ ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ , Ο€β‚‚ ∘ Ο€β‚‚ ⟩ ∘ Ο€β‚‚ ⟩
            β‰‘Λ˜βŸ¨ products! prods ⟩
          m.ΞΌ ∘ ⟨ id ∘ π₁ , m.ΞΌ ∘ Ο€β‚‚ ⟩ ∘ ⟨ π₁ , ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ ∘ Ο€β‚‚ ⟩
            β‰‘βŸ¨ extendl m.ΞΌ-assoc ⟩
          m.ΞΌ ∘ (⟨ m.ΞΌ ∘ π₁ , id ∘ Ο€β‚‚ ⟩ ∘ ⟨ ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ , Ο€β‚‚ ∘ Ο€β‚‚ ⟩) ∘ ⟨ π₁ , ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ ∘ Ο€β‚‚ ⟩
            β‰‘βŸ¨ products! prods ⟩
          m.ΞΌ ∘ ⟨ m.ΞΌ ∘ ⟨ π₁ , π₁ ∘ Ο€β‚‚ ⟩ , π₁ ∘ Ο€β‚‚ ∘ Ο€β‚‚ ⟩
            ∎
      in ⟨⟩-uniqueβ‚‚ lemma (products! prods)
        (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ pullr (⟨⟩-unique (pulll Ο€β‚βˆ˜βŸ¨βŸ© βˆ™ Ο€β‚βˆ˜βŸ¨βŸ©) (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚‚βˆ˜βŸ¨βŸ©)))
        (pulll Ο€β‚‚βˆ˜βŸ¨βŸ© βˆ™ pullr Ο€β‚‚βˆ˜βŸ¨βŸ©)