views:

167

answers:

3

I try to develop a simple average function in Haskell. This seems to work:

lst = [1, 3]

x = fromIntegral (sum lst)
y = fromIntegral(length lst)

z = x / y

But why doesn't the following version work?

lst = [1, 3]

x = fromIntegral.sum lst
y = fromIntegral.length lst

z = x / y
+10  A: 

. (composition) has a lower precedence than function application, so

fromIntegral.sum lst

is interpreted as

fromIntegral . (sum lst)

which is wrong since sum lst is not a function.

KennyTM
+8  A: 

You're getting tripped up by haskell's precedence rules for operators, which are confusing.

When you write

x = fromIntegral.sum lst

Haskell sees that as the same as:

x = fromIntegral.(sum lst)

What you meant to write was:

x = (fromIntegral.sum) lst
Daniel Martin
That's true. But I think writing operators without spaces around them sometimes leads to misunderstanding (i.e. it looks similar to construction of member accessing in many OOP-centric languages). `(fromIntegral . sum)` may cause question, but not misinterpretation.
ony
To be honest, what's confusing here isn't Haskell's precedence rules in themselves (which are easy to state) but the bewildering (to the beginner) array of operators, each with their own precedence, defined in the Prelude.
+8  A: 

I just wanted to add "$ to the rescue!":

x = fromIntegral $ sum lst
y = fromIntegral $ length lst

It has the lowest precedence and it's there to avoid too many parenthesis levels. Note that unlike (.), it doesn't do function composition, it evaluates the argument to the right and pass it to the function on the left. The type says it all:

($) :: (a -> b) -> a -> b
(.) :: (b -> c) -> (a -> b) -> a -> c
sbk
And you could also write `x = fromIntegral . sum $ lst` which is even closer to what the OP originally tried.
yatima2975
It's not *quite* accurate to say that it evaluates the argument to the right. Evaluation is still lazy. In order to evaluate the argument, you'd want `$!` instead.
Chuck
Although this solution works, I don't think it is the right answer here. To me it seems the OP is confused about operator precedence. Then the answer is to indicate the proper precedence and to point out that parentheses help here. Not to introduce yet another operator.
Martijn
@Martijn: yeah, I agree; that's why I started the answer with "I just wanted to add". KennyTM and Daniel's answers above clear up the precedence issue, I just added one extra bit of information. My answer definitely shouldn't be the accepted one, however it doesn't hurt to have it here
sbk