# A curious associativity of the <$> operator

Published on

The `<$>`

operator in Haskell is an infix synonym for `fmap`

and has the type

`(<$>) :: Functor f => (a -> b) -> f a -> f b`

For example:

```
> negate <$> Just 5
Just (-5)
```

Like all other operators, `<$>`

has a *fixity*, which can be `infixl`

, `infixr`

, or `infix`

. The fixity defines how an expression like

`abs <$> negate <$> Just 5`

is parsed.

If `<$>`

were defined as `infix`

, then the above expression wouldn’t parse at all, giving an error like

```
Precedence parsing error
cannot mix ‘<$>’ [infix 4] and ‘<$>’ [infix 4] in the same infix expression
```

If `<$>`

instead were defined as `infixr`

, then the above expression would parse as

`abs <$> (negate <$> Just 5)`

meaning first apply `negate`

to 5 inside `Just`

, and then go inside `Just`

once more and apply `abs`

.

However, `<$>`

is defined as `infixl`

, so that the applicative chains like

`+) <$> Just 5 <*> Just 6 (`

would parse correctly. This means that

`abs <$> negate <$> Just 5`

is parsed as

`abs <$> negate) <$> Just 5 (`

which is probably not what you meant. Or is it?

It turns out that if you paste that expression (either parenthesized or not) into ghci, you’ll get back `Just 5`

in all cases.

This happens because of the following instance defined in the base library:

```
instance Functor ((->) r) where
fmap = (.)
```

(Note that `(->) r`

is essentially the Reader monad, so it’s not surprising that it’s a functor.)

So the expression

`abs <$> negate) <$> Just 5 (`

does make sense and is equivalent to

`abs . negate) <$> Just 5 (`

The operators `*`

for which `a * (b * c) = (a * b) * c`

are called *associative*. Usually associative operators have the type `a -> a -> a`

(either polymorphic of for a specific `a`

), so that both ways to put parentheses typecheck.

The `<$>`

operator is curious because it doesn’t have such a type and yet is associative:

```
<$> (g <$> h) =
f {- the definition of <$> -}
fmap f (fmap g h) =
{- the definition of (.) -}
fmap f . fmap g) h =
({- the functor law -}
fmap (f . g) h =
{- the definition of <$> -}
. g) <$> h =
(f {- the Functor instance for (->) r -}
{- g has to be a function for the top expression to typecheck -}
<$> g) <$> h (f
```