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

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.

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 Ο€β‚‚βˆ˜βŸ¨βŸ©)