I'm doing Project Euler with Haskell, and found something to learn when completing the very first problem. Here's my code:
isValid x = (mod x 3 == 0) || (mod x 5 == 0)
listValid :: Integer -> [Integer]
listValid n = [x | x <- [1..n-1], isValid x]
The function listValid
will get all the positive integers less than n
that are divisble by either 3 or 5. Easy enough.
*Main> listValid 10
[3,5,6,9]
Now I need to sum them. I figure the sum function is the right way to do this. What I don't understand is why the first two versions work, and then third doesn't.
*Main> sum (listValid 10)
23
*Main> sum $ listValid 10
23
*Main> sum listValid 10
<interactive>:4:5:
Couldn't match type ‘[Integer]’ with ‘a0 -> t’
Expected type: Integer -> a0 -> t
Actual type: Integer -> [Integer]
Relevant bindings include it :: t (bound at <interactive>:4:1)
In the first argument of ‘sum’, namely ‘listValid’
In the expression: sum listValid 10
Is this an order of operations problem, where I need to wrap in parentheses to assert which function should be applied first? And if so, what is the $
doing in the second version?
It's about associativity. Function application is left-associative, so sum listValid 10
is equivalent to (sum listValid) 10
, not sum (listValid 10)
. And if you think about it, it has to be that way: If you define add x y = x+y
, you wouldn't want add 1 2
to be equivalent to add (1 2)
.
So the issue here is that in sum listValid 10
, it doesn't see listValid 10
as the argument to sum
; it sees listValid
as the argument to sum
and then 10
as the argument to sum listValid
.
$
resolves this issue because it's an infix operator and it's perfectly clear that sum
is its left operand and listValid 10
is its right operand (keeping in mind that function application has higher precedence than any infix operator, so it can't be seen as (sum $ listValid) 10
).