Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functor is for (a -> b) -> (f a -> f b), what is for (Category c) => c a b -> c (f a) (f b)?

I would like to have a function for either mapping a pure function to a container or sequencing applicative/monadic action through it. For pure mapping we have

fmap :: Functor f => (a -> b) -> (f a -> f b)

For monadic sequencing we have (from Data.Taversable)

mapM :: (Traversable f, Monad m) => (a -> m b) -> (f a -> m (f b))

Which is similar to

mapKleisli :: (Traversable f, Monad m) => Kleisli m a b -> Kleisli m (f a) (f b)
mapKleisli = Kleisli . mapM . runKleisli

We know both (->) and (Kleisli m) are categories (and arrows). So it's naturally to make a generalization:

mapCategory :: (X f, Category c) => c a b -> c (f a) (f b)

Do you know such a class X with similar method? Maybe, somewhere on hackage? I tried to hoogle/hayoo but haven't found anything appropriate.

Update:

Now I know better what I need. Both Kleisli arrows and (->) are instances of ArrowApply which is as powerful as Monad. I came up with this arrow-based version of Travesable:

{-# LANGUAGE TypeOperators #-}

import Prelude hiding (id, (.), mapM)
import Control.Arrow
import Control.Category

class Traversable f where
  traverse :: ArrowApply (~>) => f a -> (a ~> b) ~> f b

mapArrow :: (ArrowApply (~>), Traversable f) => a ~> b -> f a ~> f b
mapArrow a = arr (\x -> (traverse x, a)) >>> app

instance Traversable Maybe where
  traverse Nothing = arr (const Nothing)
  traverse (Just x) = arr (\a -> (a, x)) >>> app >>> arr Just

instance Traversable [] where
  traverse [] = arr (const [])
  traverse (x : xs) = undefined -- this is hard!

I could use just usual Applicative-based Traversable, with Identity for pure functions, but I'm not sure it is good. Considering pure functions as special case of monadic actions is weird. Interpreting both pure functions and monadic actions as instances of some action class (Category/Arrow/ArrowApply) looks more straightforward to me.

Questions: would you like to finish instance for []? Has my opinion about ArrowApply vs Monad any sense?

like image 996
modular Avatar asked Jun 22 '11 19:06

modular


People also ask

Is functor a type class?

Functor is a type class that abstracts over type constructors that can be map 'ed over. Examples of such type constructors are List , Option , and Future .

What is functor in Haskell?

Functor in Haskell is a kind of functional representation of different Types which can be mapped over. It is a high level concept of implementing polymorphism. According to Haskell developers, all the Types such as List, Map, Tree, etc. are the instance of the Haskell Functor.

Is maybe a functor Haskell?

Another simple example of a functor is the Maybe type. This object can contain a value of a particular type as Just , or it is Nothing (like a null value).

Is every applicative a Monad?

Monads are not a replacement for applicative functors Instead, every monad is an applicative functor (as well as a functor). It is considered good practice not to use >>= if all you need is <*>, or even fmap.


1 Answers

You're asking for "some class X", but it should be pretty clear that the most (or perhaps, only) correct name for this class would be "Functor". What you want is simply a functor class defined for an arbitrary Category instance, rather than limited to (->).

Of course, your definition is still limited to (endo)functors from a category to a subcategory defined by the type constructor giving the instance. If you generalize a bit further, there's no reason for the two categories to be the same, giving you a type class something like this one:

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)

This is still awfully limited vs. the full concept of a functor in category theory, but oh well.

It's also interesting to observe that this still has a (->) type constructor in it--that's because, even though we're modeling the source and target categories with arbitrary instances, the whole thing (and in particular, the functor itself) still exists in some sense in Hask, i.e., the category associated with (->). The other half of the functor (the part mapping objects) is, roughly speaking, the (->) in the kind * -> * for the type constructor f.

like image 168
C. A. McCann Avatar answered Oct 18 '22 03:10

C. A. McCann