(.)
and (<=<)
are quite similar:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
and are available as a method in the Category
type class ((->)
and Kleisli
instances):
(<<<) :: (Category f) => f b c -> f a b -> f a c
($)
and (=<<)
are also quite similar:
($) :: (a -> b) -> a -> b
(=<<) :: Monad m => (a -> m b) -> m a -> m b
Is there a type class that abstracts over these application functions?
Both your examples are arrow mappings of functors (not Functors
, but functors in the broader categorical sense), just like fmap
is the arrow mapping of a Functor
. (=<<)
, for instance, is the arrow mapping of a functor from Kleisli m
to (->)
for some monad m
. An appropriate generalisation, then, is one that accounts for functors between different categories. Control.Categorical.Functor
provides that:
class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
fmap :: r a b -> t (f a) (f b)
Armed with that, you would be able to write an instance in the spirit of:
-- `(.)` is plain old Prelude `(.)`, and not the generalised `Category` one.
instance Monad m => Functor m (Kleisli m) (->) where
fmap = (=<<) . runKleisli
Or, for something you can actually run:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Arrow (Kleisli(..))
import qualified Control.Categorical.Functor as F
newtype BindF m a = BindF { runBindF :: m a }
deriving (Functor, Applicative, Monad, Show)
instance Monad m => F.Functor (BindF m) (Kleisli (BindF m)) (->) where
fmap = (=<<) . runKleisli
GHCi> F.fmap (Kleisli (BindF . replicate 2)) (BindF [1,2,3])
BindF {runBindF = [1,1,2,2,3,3]}
A similar instance might be written, for instance, for (<*>)
, in terms of the Static
category. As for ($)
, it is the arrow mapping of the identity functor in (->)
, and so it is merely fmap
for Identity
sans the Identity
wrapper (cf. Daniel Wagner's comment to the question).