Application of functions and Kleisli arrows

204 Views Asked by At

(.) 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?

2

There are 2 best solutions below

0
On BEST ANSWER

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).

0
On

As Daniel's comment says, (=<<) already encompasses ($). There is already a newtype (similar to how there is a Kleisli newtype for a -> m b for Category) for a called Identity, which has a Monad instance such that

f $ x

corresponds to

Identity . f =<< Identity x

While there are subcomponents that are reused in (.) and (<=<) (namely a -> b in the former and a -> m b in the latter) which can be abstracted out to a typeclass for a type constructor a :: * -> * -> * (which turns out to be Category), the largest such subcomponent in ($) and (=<<) is just a in the former and m a in the latter.