I haven’t worked out how to make the svg live on the haddocks yet, but numhask includes something like this, for its class structure, but where the boxes link to the haddocks of each class:
The functionality is published in dotparse. If there’s any interest, I could do the same for these flowcharts.
Very curious that back in the day the relation between Monad and Functor did not exist. I was aware that Applicative was discovered much later, but I had never suspected that Monad and Functor used to be totally unrelated!
If a monad is just a monoid in the category of endofunctors, then why these classes are totally isolated from each other?
Because Monad
doesn’t represent all mathematical monads (just a very restricted subset) nor does Monoid
represent all mathematical monoids.
Sometimes I wish Category
from base is a bit more generalized:
{-# LANGUAGE TypeFamilies #-}
import Data.Kind (Constraint, Type)
import qualified GHC.Base (id, (.))
class Hask a; instance Hask (a :: Type)
-- Compatible with base category by default CategoryObj to all Types
class Category cat where
type family CategoryObj cat :: Type -> Constraint
type instance CategoryObj cat = Hask
id :: CategoryObj cat a => cat a a
(.) :: (CategoryObj cat a, CategoryObj cat b, CategoryObj cat c) => cat b c -> cat a b -> cat a c
class MyBizzaroObj a
data (:->) a b = (MyBizzaroObj a, MyBizzaroObj b) => a :-> b
instance Category (:->) where
type instance CategoryObj (:->) = MyBizzaroObj
id = undefined -- some bizzaro stuff
(.) = undefined
I vaguely recall index-core: Indexed Types is somewhat related.
I would say the reason is that for you to be able to have Monad related to Monoid, via “Monoid in the Category of Endofunctors” you’d have to have a different structure to the type class hierarchy. A Categorical one, which was not the original type class hierarchy path that Haskell took.
Indeed, however there are two ways of doing it (let’s forget Applicative). The current one
class Functor m => Monad m where ...
This forces you to implement fmap
explicitely. Or something I which could be done
instance Monad m => Functor m where ...`
The first says a Monad needs to be a Functor (in anoher Monad implies being a Functor which could be written Monad => Functor
(the reverse of the actual notation). In other way, every Monad has to be a Functor.
The second is saying a Monad implies a Functor (Monad => Functor
agin), given any Monad I can make it a Functor instance (because I can implement fmap
in term of >>=
and return
).
In other words, every Monad is a Functor ( and I don’t need to do anythig about it).
I remember at the time it to be annoying to have to define fmap
even though it was already done in the Monad instance.