Why does <$> only affect the second member of the pair?

Take a look at the following interactive session in GHCi:

  Prelude> import Control.Applicative
 Prelude Control.Applicative> (+1) <$> [1,2]
 [2,3]
 Prelude Control.Applicative> (+1) <$> (1,2)
 (1.3)

I think there is a good reason for the <$> behavior regarding pairs, but so far I have not been able to find it, therefore:

why is <$> (or `fmap` ) defined for action only on the second member of a pair, and not on both values?

+6
source share
3 answers

<$> (aka fmap ) is a member of the Functor class as follows:

 class Functor f where fmap :: (a -> b) -> fa -> fb 

Thus, any f must be a parameterized type with one type argument. Lists are one of those types when they are written in their prefix form [] ( [] a matches [a] ). So, an instance for lists:

 instance Functor [] where -- fmap :: (a -> b) -> [] a -> [] b fmap = map 

Pairs can also be written as a prefix: (,) ab matches (a, b) . Therefore, consider what we do if we want a Functor instance to include pairs. We cannot declare instance Functor (,) , because the constructor of the pair (,) takes two types - and they can be of different types! What we can do is declare an instance for (,) a - the type that is needed only for the following type:

 instance Functor ( (,) a ) where -- fmap :: (b -> c) -> (,) ab -> (,) ac fmap f (x, y) = (x, fy) 

Hopefully you will see that the definition of fmap is the only reasonable one we can give. The answer to the question why the functor instance works in the second element in the pair is that the type of the second element comes last in the list! We cannot easily declare an instance of a functor that works with the first element in a pair. By the way, this generalizes to large tuples, for example. four (,,,) abcd (aka (a, b, c, d) ) can also have a Functor instance for the last element:

 instance Functor ( (,,,) abc) where -- fmap :: (d -> e) -> (,,,) abcd -> (,,,) abce fmap f (p, q, r, s) = (p, q, r, fs) 

Hope this helps explain all this!

+15
source

Consider the definition of a functor typeclass:

 class Functor f where fmap :: (a -> b) -> fa -> fb 

Obviously, f has the form * -> * . That way, you can only declare instances for a data type that has the form * -> * . What you can do is this:

 instance Functor (,) where fmap :: (a -> b) -> (,) a -> (,) b 

This will work on partitial applicated tuples and is really inconvenient. So, one of them defined an example:

 instance Functor ((,) a) where fmap :: (b -> c) -> (,) ab -> (,) ac fmap f (x,y) = (x,fy) 

In short: it is not possible in simple Haskell 98 (although I believe there is a syntax extension there) to define an instance as

What you can do is define your own tuple:

 data T a = T aa instance Functor T where fmap f (T ab) = T (fa) (fb) 

Then you can do whatever you want. You see, because the view * -> * instead of * -> * -> * , everything is in order.

+3
source

I assume that the tuple should not be homogeneous, I mean that both types can be different. If you need a uniform tuple, you can use a list, and then fmap will work.

How would you expect (+1) ("Hello", 2) to work?

 Prelude> import Control.Applicative Prelude Control.Applicative> (+1) <$> ("hello",2) ("hello",3) 

It just works, but there is no particular behavior when both types are the same. By the way, I do not know why the second value is not used, and not the first, but in any case, you can use only one value.

+2
source

All Articles