A curious associativity of the <$> operator

Published on

The <$> operator in Haskell is an infix synonym for fmap and has the type

For example:

Like all other operators, <$> has a fixity, which can be infixl, infixr, or infix. The fixity defines how an expression like

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

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

would parse correctly. This means that

is parsed as

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:

(Note that (->) r is essentially the Reader monad, so it’s not surprising that it’s a functor.)

So the expression

does make sense and is equivalent to

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: