Why Functor class has no return function?
Asked Answered
S

5

23

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.

Stipulation answered 8/2, 2014 at 15:12 Comment(9)
What do you mean by "situation is completly opposite for Functor and for Monad classes"? Since monads are functors, it can't be opposite. — As for "why category theory argument is applicable to Haskell type theory": type theory has nothing to do with this whatsoever. It's just the Haskell standard libraries, they implement type classes which are modelled after category theory concepts.Abc
@Abc Yes, and I wonder why they are opposite, despite the fact that they can not (: The point is that I was thinking 'return' is part of mathematical functor mapping objects of Hack. But really return is representing natural tranformation, which is defined for every Monad.Stipulation
In category theory, a functor maps two things: objects to objects and arrows to arrows. In Haskell, a functor also maps two things: values to values and types to types.Essentiality
Exactly, return is representing the natural transformation η: 1 → T, which is defined for every monad but not for general functors. So... what's still not clear to you?Abc
@DavidYoung "values to values and types to types" ???Stipulation
@Abc Yes, that is exactly that I had not understand. Now everything is clear, just SO is locking.Stipulation
In instance Functor f where ..., f is something that takes a type and gives you another type (so it is a mapping between types). For example Maybe is a type constructor that takes a type and gives you a type. If you give it Int, then it gives you Maybe Int. fmap maps f a values to f b values given a function a -> b.Essentiality
@DavidYoung "fmap maps f a values to f b values given a function a -> b." interpretation is unclear to me, and is not related to mathematical definition. Why it is beter than just think fmap as map of arrows of Hask?Stipulation
I didn't word that very well. fmap takes a function from a -> b and maps it to a function from f a -> f b. As I understand it, this is analogous to the arrow mapping done by category theoretic functors. It takes an arrow in the category Hask, and it maps it to an arrow in the category Hask where all types have an f applied to them. So in the Maybe example, it maps arrows from Hask to the category of Haskell types where all types are applied to Maybe: fmap :: (a -> b) -> (Maybe a -> Maybe b).Essentiality
T
16

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

fmap :: (α -> β) -> (F α -> F β)

The important thing is that return :: α -> M α of Monad is not a mapper of a type α to the M α as you might think. According to the mathematical definition of a monad, return corresponds to a natural transformation from Id functor to the M functor. And the Id functor is kind of implicit in Hask. The standard definition of a monad also requires another natural transformation M ◦ M -> M. So translating it to Haskell would look 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 from 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.

Tool answered 3/3, 2014 at 12:22 Comment(0)
A
8

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)
Abc answered 8/2, 2014 at 15:23 Comment(2)
Yes, that is definitely what's i am talking about. Functor consists of two morphisms, but in Haskell one of them is simply function and another is type-level entity.Stipulation
That's not quite correct. If you'd like to see functors as morphisms, then it's just one: in the category of categories, the objects are categories and a morphism between category A and category B is a functor that maps objects of A to objects of B as well as morphisms of A to morphisms of B. In the example, Maybe is an endofunctor of Hask, i.e. an endomorphism in the category of categories, and as I said it maps objects to objects (e.g. the type Int to type Maybe Int) and morphisms to morphisms (length :: String -> Int to fmap length :: Maybe String -> Maybe Int)Abc
T
7

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.

Tharp answered 26/3, 2014 at 12:43 Comment(1)
Exelent addition! Thank you.Stipulation
S
4

If you have

instance Functor F where
    fmap = ...

Then the type constructor F is the action on objects (which are types) taking a type T to the type F T, and fmap is the action on morphisms (which are functions) taking a function f :: T -> U to fmap f :: F T -> F U.

Savaii answered 8/2, 2014 at 15:41 Comment(4)
But why there is no special function, like in the case of monads?Stipulation
What do you mean? The case of monad is no different.Savaii
Every Monad type M has an function return :: a -> M a. But functor type F has no function return :: a -> F a.Stipulation
That doesn't map objects to objects though. In category theory terms, its a morphism.Savaii
S
0

In category theory, a functor maps all the objects from a category to another, but a functor doesn't map the elements in the objects.

Schreibe answered 20/9, 2022 at 19:30 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.