return : a -> T a
join : T (T a) -> T a
functor :
object mapping: T : Type -> Type
morphism mapping :
(a -> b)
---------
T a -> T b
return : a -> T a
extension :
(a -> T b)
------------
T a -> T b
T : Type -> Type
Kleisli form is conceptually handier in Programming
c.f. UArray (UArray a) -> UArray a
(undefined in Haskell)
vs. (a -> UArray b) -> UArray a -> UArray b
(defined when
a
and b
and unboxable).
c.f. Set (Set a) -> Set a
Sets are not necessarily orderable, cf. {1, 5}
and {3, 4}
but (a -> Set b) -> Set a -> Set b
okay if a
and b
are orderable.
In Haskell, Functor is actually analogous to endofunctors (map from Hask to Hask)
class Functor f where
fmap :: (a -> b) -> f a -> f b
i.e., f : Hask -> Hask or in Haskell
notation f : Type -> Type
e.g. List : Hask -> Hask
But a more general structure would map from subcategories of Hask to Hask:
class ExoFunctor f where
type SubCat f :: * -> Constraint
exfmap :: (SubCat f a, SubCat f b) => (a -> b) -> f a -> f b
e.g. Set : Ord -> Hask
Another way of writing this is with exposed parameters:
class ExoFunctor f a b where
exfmap :: (a -> b) -> f a -> f b
But this scales very poorly (have to "export" every type variable in the instance head, makes constraints very long).