My understanding is that the difference between map and fmap is that the latter can return a function?
I'm studying the functors section of this http://learnyouahaskell.com and some of the explanation is a bit unclear.
Map and fmap behave identically in the following:
let exMap = map (+1) [1..5]
let exFMap = fmap (+1) [1..5]
What is a good example of an fmap returning a function?
3 Answers 3
No, the difference is that fmap applies to any functor. For instance:
readLine :: IO String -- read a line
fmap length readLine :: IO Int -- read a line and count its length
Just 4 :: Maybe Int
fmap (+10) (Just 4) :: Maybe Int -- apply (+10) underneath Just
-- returns (Just 14)
map turns a -> b into a function [] a -> [] b (usually written as [a] -> [b]).
fmap turns a -> b into a function f a -> f bfor any functor f, not only for f = []. The examples above chose f = IO and f = Maybe.
3 Comments
a->b and f a, when f is a functor, you can get f b using fmap. However, if you have f (a->b) and f a, you can not get f b: the function is wrapped underneath f and there's no way to make it interact with its argument. Applicative functors instead define an additional operation <*> allowing for that.It would help to look at the type signatures for each function, let's start with the map function you are looking at:
map :: (a -> b) -> [a] -> [b]
As you can see, this map function operates on lists. Logically however, there are many data structures which can be mapped over. Here are some other possible maps:
map :: (a -> b) -> Map k a -> Map k b
map :: (a -> b) -> Maybe a -> Maybe b
map :: (a -> b) -> IO a -> IO b
This is just the tip of the iceberg, many things can be mapped!
In languages that don't support type classes, this could be the world as you know it. There are simply many map functions and you have to qualify them with an appropriate module type to distinguish which map you actually mean. Not so in Haskell!
Now let's look at fmap:
fmap :: Functor f => (a -> b) -> f a -> f b
This function has exactly the same form as those shown above but works on anything which is a functor.
Functor is defined like this:
class Functor f where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
(<$) = fmap . const
Hopefully this makes it obvious that a functor is simply something that supports being mapped over.
Therefore fmap is general, while map is specific.
3 Comments
fmap over Text or ByteString, though, since they are not functors.fmap is more general than map - and indeed for lists there is no difference - here you have map == fmap.
Let us begin with the definition of fmap
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
this essentially says you can turn a simple function into a function that transforms containers into containers of the same shape but different elements.
instance Functor [] where
fmap = map
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just something) = Just (f something)
there are many more, I think almost every container with a single type parameter can be a functor
As an exercise you can try to define an instance for
data Tree a = Tree a [a]
for the usage of fmap see @chi's answer.