Costate comonad coalgebras

August 1, 2014

Every now and then you hear that lenses are actually just “costate comonad coalgebras”.

data State s a = State (s -> (a, s))

The State monad we all know and love. Given a state s, produce a value a and a new s.

data Store s a = Store (s -> a) s

The Store type, which is dual to State. It’s sometimes called CoState. The idea of this type is that we take a “piece” out of our a value of type s. We also give a way to insert the s back into a, making it whole again.

instance Functor (Store s) where
  fmap f (Store p x) = Store (f . p) x

If we have a way to turn an a into a b, then we can essentially consider the s to be a piece of b as well.

fmap id (Store p x)
= Store (id . p) x
= Store p x

Thus fmap id = id, making sure that Store s is actually a Functor. The second Functor law is redundant, so we don’t have to prove it.

instance Comonad (Store s) where
  extract (Store p x)   = p x
  duplicate (Store p x) = Store p' x
    where p' s = Store p s

To extract the whole value of the Store, simply apply the piece to the builder. To duplicate it, we construct a modified Store to return a Store s a when it becomes whole again. Since s is arbitrary, our only choice is to just use the one we’ve given. Our building function has to construct a Store, so we just pass it the s we’re given and use the builder from the original Store.

extract (duplicate (Store p x))
= extract (Store (\s -> Store p s) x)
= (\s -> Store p s) x
= Store p x

Thus extract . duplicate = id.

fmap extract (duplicate (Store p x))
= fmap extract (Store (\s -> Store p s) x)
= Store (\s -> extract (Store p s)) x
= Store (\s -> p s) x
= Store p x

Thus fmap extract . duplicate = id.

duplicate (duplicate (Store p x))
= ... -- Fill in later (AKA, exercise left to reader)
= fmap duplicate (duplicate (Store p x))

Thus duplicate . duplicate = fmap duplicate . duplicate, and we have shown that Store s satisfies all of the Comonad laws.

type Coalgebra f a = a -> f a

For a given Functor f and type a, a map a -> f a is known as an F-coalgebra. If the Functor is a Comonad and the map preserves the comonadic structure, then this is known as a comonad coalgebra.

type Lens s a = Coalgebra (Store s) a
              = a -> Store s a
              = a -> (s -> a, s)

So there you have it: a Lens gives us a way to take a value and form a Store out of it. For a more detailed look, see Relating Algebraic and Coalgebraic Descriptions of Lenses by Jeremy Gibbons and Michael Johnson.