开发者

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?


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜