Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Functor class has no return function?

From categorical point of view, functor is pair of two maps (one between objects and another between arrows of categories), following some axioms.

I have assumed, what every Functor instance is similar to mathematical definition i.e. can map both objects and functions, but Haskell's Functor class has only function fmap which maps functions.

Why so?

UPD In other words:

Every Monad type M has an function return :: a -> M a.

And Functor type F has no function return :: a -> F a, but only F x constructor.

like image 209
uhbif19 Avatar asked Feb 08 '14 15:02

uhbif19


People also ask

Is functor a function?

A functor (or function object) is a C++ class that acts like a function. Functors are called using the same old function call syntax.

Is functor a type class?

Functor in Haskell is a typeclass that provides two methods – fmap and (<$) – for structure-preserving transformations. To implement a Functor instance for a data type, you need to provide a type-specific implementation of fmap – the function we already covered.

What is functor category theory?

In category theory, a branch of mathematics, a functor category is a category where the objects are the functors and the morphisms are natural transformations between the functors (here, is another object in the category).

What is a functor vs function?

Functors are objects that behave as functions. They are class objects which can overload the function operator() and act as function themselves. They can encapsulate their own function which is executed when needed.


3 Answers

First of all, there are two levels: types and values. As objects of Hask are types, you can map them only with type constructors, which have the * -> * kind:

  • α -> F α (for Functor F),
  • β -> M β (for Monad M).

Then for a functor you need a map on morphisms (i.e. functions, which are values): it's just fmap :: (α -> β) -> (F α -> F β).

So far, I guess, I'm not saying anything new. But important thing is that return :: α -> M α of Monad is not a mapper of a type α to the M α as you may think. Regarding to the math definition of a monad, return corresponds to a natural transformation from Id functor to the M functor. Just that this Id functor is kind of implicit. The standard definition of monad requires also another natural transformation M ◦ M -> M. So translating it to Haskell would be like

class Functor m => Monad m where
    return :: Id α -> m α
    join :: m (m α) -> m α

(As a side-note: these two natural transformations are actually the unit and multiplication, which make monad a monoid in the category of endofunctors)

The actual definition differs but is equivalent. See Haskell/wiki on that.

If you take the composition-like operator derived form the standard bind >>= :: m α -> (α -> m β) -> m β:

(>=>) :: Monad m => (α -> m β) -> (β -> m γ) -> (α -> m γ)
f >=> g = \a => f a >>= g

you can see, that it's all actually about the Kleisli category. See also the article on nLab about monads in computer science.

like image 87
laughedelic Avatar answered Nov 11 '22 06:11

laughedelic


Objects of a category are not the same as objects in a OO programming language (we prefer to call those values in Haskell; what they mean in category theory was discussed here). Rather, the objects of Hask are types. Haskell Functors are endofunctors in Hask, i.e. associate types to types, by the following means:

Prelude> :k Maybe
Maybe :: * -> *
Prelude> :k Int
Int :: *
Prelude> :k Maybe Int
Maybe Int :: *

OTOH, the arrows of Hask are in fact values, of some function type a -> b. These are associated in the following way:

fmap :: ( Functor (f ::   t     ->     f t       {- type-level  -} ) )
             =>         (a->b)  ->  fmap(a->b)   {- value-level -}
                     ≡  (a->b)  ->  (f a->f b)
like image 30
leftaroundabout Avatar answered Nov 11 '22 05:11

leftaroundabout


Though you were using those fancy categorical terms in your question and should be completely satisfied with the existing answers, here is an attempt for a rather trivial explanation:

Suppose there would be a function return (or pure or unit or ...) in the Functor type class.

Now try to define some common instances of Functor: [] (Lists), Maybe, ((,) a) (Tuples with a left component)

Easy enough, eh?

Here are the ordinary Functor instances:

instance Functor [] where
   fmap f (x : xs) = f x : fmap xs
   fmap _ []       = []

instance Functor Maybe where
   fmap f (Just x) = Just (f x)
   fmap _ Nothing  = Nothing

instance Functor ((,) a) where
   fmap f (x, y) = (x, f y)

What about return for Functor now?

Lists:

instance Functor [] where
   return x = [x]

Alright. What about Maybe?

instance Functor Maybe where
   return x = Just x

Okay. Now Tuples:

instance Functor ((,) a) where
   return x = (??? , x)

You see, it is unknown which value should be filled into the left component of that tuple. The instance declaration says it has a type a but we do not know a value from that type. Maybe the type a is the Unit type with only one value. But if its Bool, should we take True or False? If it is Either Int Bool should we take Left 0 or Right False or Left 1?

So you see, if you had a return on Functors, you could not define a lot of valid functor instances in general (You would need to impose a constraint of something like a FunctorEmpty type class).

If you look at the documentation for Functor and Monad you will see that there are indeed instances for Functor ((,) a) but not for Monad ((,) a). This is because you just can't define return for that thing.

like image 25
scravy Avatar answered Nov 11 '22 06:11

scravy