I am looking to understand what does Representable stand for in Haskell. The definition
Representable endofunctors over the category of Haskell types are
Representable
s are containter-like functors that have a "special relationship" with another type that serves as an index into the Representable
. In the Haskell definition, this index type is given by the associated type family type Rep f :: *
For every value of the index and for every value of the Representable
, we can call the index :: f a -> Rep f -> a
function to get the corresponding element. And tabulate :: (Rep f -> a) -> f a
constructs a container where each element is derived from its own index.
Now, here is an example of a functor that is NOT representable: the typical Haskell list type []
. One might naively think that it can be indexed by something like a Natural, but the problem is that lists can be empty, or not have enough elements to reach a given index.
An always-infinite type like data Stream a = Stream a (Stream a)
is Representable
and it's indexed by Natural
, because there will always be a value for any given Natural
that we pass to index
.
Similarly, the homogeneous pair data Pair a = Pair a a
is indexed by the type Bool
: the index tells us which of the components to select.
If we get dependent-ish, fixed-size vectors are Representable
and are indexed by finite naturals bounded by the size of the vector. They aren't indexed by unbounded Natural
s because then we could have an out-of-bounds access!
Reading the various instances defined for Representable
is instructive, but it seems we have to get down to the source code because the associated types are not visible in the Haddocks. Some interesting tidbits:
The Identity
functor is indexed by the unit type ()
, this makes sense because Identity
only has one "slot" so to speak, so we don't need to provide any information.
The "functions from some type" type ((->) e)
is indexed by the source type itself. And index
is simply id
. This is what's meant by "isomorphic to the reader monad", because the Reader e
monad is just a newtype over ((->) e)
.
The Composition (nesting) of two representable functors is again Representable
, and it is indexed by the pair of the original indexes! This makes sense: first we must know how to index into the outer functor, and then into the inner one.
The Product (pairing) of two Representable
functors is indexed by the sum (Either
) of the original indexes. The branch of the Either
tells us in which part of the product to index.
A notable omission (because it is not true in general): there is no (Representable f, Representable g) => Representable (Sum f g)
instance.