A category C
consists of:
Obj(C)
;Hom(C)
) of morphisms between those objects. If a
and b
are in Obj(C)
, then a morphism f
in Hom(C)
is typically denoted f : a -> b
, and the collection of all morphism between a
and b
is denoted hom(a,b)
;a : Obj(C)
there exists a morphism id : a -> a
;.
), taking two morphisms f : a -> b
, g : b -> c
and producing a morphism a -> c
which obey the following laws:
For all f : a -> x, g : x -> b, then id . f = f and g . id = g
For all f : a -> b, g : b -> c and h : c -> d, then h . (g . f) = (h . g) . f
In other words, composition with the identity morphism (on either the left or right) does not change the other morphism, and composition is associative.
In Haskell, the Category
is defined as a typeclass in Control.Category:
-- | A class for categories. -- id and (.) must form a monoid. class Category cat where -- | the identity morphism id :: cat a a -- | morphism composition (.) :: cat b c -> cat a b -> cat a c
In this case, cat :: k -> k -> *
objectifies the morphism relation - there exists a morphism cat a b
if and only if cat a b
is inhabited (i.e. has a value). a
, b
and c
are all in Obj(C)
. Obj(C)
itself is represented by the kind k
- for example, when k ~ *
, as is typically the case, objects are types.
The canonical example of a Category in Haskell is the function category:
instance Category (->) where id = Prelude.id (.) = Prelude..
Another common example is the Category
of Kleisli
arrows for a Monad
:
newtype Kleisli m a b = Kleisli (a -> m b) class Monad m => Category (Kleisli m) where id = Kleisli return Kleisli f . Kleisli g = Kleisli (f >=> g)