The (.)
operator is for composing functions, not values, and what it returns is a function, not a value. This is because f . g
is defined as the function which you get as running g
on its input, then running f
on the result of that:
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \a -> f (g a)
Given this, let’s look at your non-working example again, which I will re-bracket to make the situation a little clearer:
sum . map square [1..n]
== (sum) . (map square [1..n])
Immediately, we can see a problem: map square [1..n]
is not a function! This means we cannot run it on an input, which in turn means that sum . map square [1..n]
would make no sense.
So what does make sense? Well, we could do sum . map square
instead. Now both of the arguments of (.)
are functions: sum
sums its input (which must be a list of numbers), and map square
applies square
to each element of its input (which must be a list of numbers). Thus, their composition makes sense, the types all line up, and we can use (.)
with no problems. We can then feed an input to this composite function, by doing (sum . map square) [1..n]
.
Another option is to use ($)
rather than (.)
. This operator is defined as follows:
f $ x = f x
That is, ($)
simply applies the function on its left to the value on its right! This might seem a bit useless… but the nice thing about ($)
is that it has a very low precedence, lower than almost anything else in Haskell. In short, this means that it has the effect of ‘bracketing’ everything to its right. Thus, it’s fine to write:
sum $ map square [1..n]
…because this is equivalent to:
sum (map square [1..n])
…which is what you’re trying to do. (For more on the difference between (.)
and ($)
, I refer you to What is the difference between . (dot) and $ (dollar sign)? .)