Functor monads from Hask, the Haskell type and function category, to Hask --- endofunctor. This means that some of the arrows in Hask look like a -> mb for some Monad m . For a particular monad m Hask subcategory, where the arrows look like a -> mb , is the Claysley category for m .
We know that this is a category because the identity exists arrow return :: a -> ma and composition (>>>) :: (a -> mb) -> (b -> mc) -> (a -> mc) defined as
(f >>> g) a = join (g <$> fa)
so we need it to be Monad --- we use both return and join .
In Haskell, we cannot just have a subcategory in normal mode, but instead use a new type.
import Prelude hiding ((.), id) import Control.Category newtype Kleisli mab = Kleisli { runKleisli :: a -> mb } instance Monad m => Category (Kleisli m) where id = Kleisli return Kleisli g . Kleisli f = Kleisli (join . fmap g . f)
And then we can update functions like Monad m => a -> mb to Kleisli mab s, arrows in the category and put them together with (.)
arr :: Kleisli IO FilePath [String] arr = Kleisli (mapM $ fmap show . getModificationTime) . Kleisli getDirectoryContents
This is usually a little syntactically noisy. The new type is only useful for using the Category class to overload id and (.) . Instead, it is more likely that you will see return and (>=>) which are equivalent
return a = runKleisli (id a) f >=> g = runKleisli $ Kleisli g . Kleisli f
J. abrahamson
source share