map example in Effective Haskell (B2.0), Page 58

Viewed 62

Just so you know, I am somewhat familiar with Haskell but not totally comfortable with it yet so I was going through the book 'Effective Haskell' which is still in early release at PragPub. I ran into the following.

In the discussion of map on page 58 the author presents the example:

map ($ 10) [(+1), (*3), (`div` 5)]

which results in [11, 30, 2]

This confuses me a lot. The function application operator ($) was introduced back on page 15 as a way of forcing validation of arguments prior to the evaluation of the function. In that case the $ comes after the function but before the arguments.

Here we have the $ 10 as the function argument to map. I look at this example and it seems to be completely backward. I know what is intended but I just cannot make sense of how it works. In fact, the 'div' piece is a great example of where I go off the rails trying to understand this. If I execute

div 5 $ 10 

in ghci I get the result 0. And, of course, this doesn't work at all:

$ 10 `div` 5 

or even

$ 10 div 5

So what this really does is

div 10 5

After playing around in ghci a bit I finally realized that this is equivalent to

10 `div` 5

So I then tried

($ 10) (`div` 5)

and also got the right answer.

But what I don't understand is why is the $ operator needed here? What does it do? Why doesn't the following work, instead:

map 10 [(`div` 5)]

Since that seems it should be equivalent to

10 `div` 5

But when I try that map expression I get an error that doesn't make any sense to me about a non type-variable argument in the constraint... So I am at a loss when trying to understand this example.

1 Answers

Ok. I may have figured this out (but I would like someone to verify I have it right).

$ is an infix function and ($ 10) partially applies the right-hand argument to the function. So it is waiting for the left-hand argument (another function). In fact, the type of ($ 10) is

Num a => (a -> b) -> b

Now the other half of the problem:

(`div` 5) 

is also a partially-applied infix function (by virtue of the back-ticks). It is waiting on its left-hand argument. Let's call this d. But the salient fact it that d is now a function Int -> Int.

So d is passed to ($ 10). But the effect is that the 10 is passed to d which, by virtue of the partial application, is waiting for the left-hand argument resulting in

10 `div` 5

Does that sound right?

Related