2

Beginning to learn Haskell:

*Main> map double [1,2,3]
[2,4,6]

*Main> sum (map double [1,2,3])
12

*Main> (sum . map) (double) ([1,2,3])

<interactive>:71:8:
Couldn't match type ‘[b0] -> [b0]’ with ‘[[t0] -> t]’
Expected type: (b0 -> b0) -> [[t0] -> t]
  Actual type: (b0 -> b0) -> [b0] -> [b0]
Relevant bindings include it :: t (bound at <interactive>:71:1)
Probable cause: ‘map’ is applied to too few arguments
In the second argument of ‘(.)’, namely ‘map’
In the expression: sum . map

According to this answer: Haskell: difference between . (dot) and $ (dollar sign) "The primary purpose of the . operator is not to avoid parenthesis, but to chain functions. It lets you tie the output of whatever appears on the right to the input of whatever appears on the left.".

OK, so why my example does not work? Actual and expected types are different, but why? After all, according to this description map should take (double) ([1,2,3]) on the input and pass its output to sum's input?

Community
  • 1
  • 1
LetMeSOThat4U
  • 6,470
  • 10
  • 53
  • 93

1 Answers1

7

The reason for this is that . only allows the function to take one argument before being passed to the next. So:

(sum . map) double [1,2,3]

Will become

(sum (map double)) [1,2,3]

...and we can't sum a function, can we? Type error galore!

What you'll want to do is this:

(sum . map double) [1,2,3]

which reduces to:

sum (map double [1,2,3])

If you want to see, here's how . is defined:

(.) :: (b -> c) -> (a -> b) -> (a -> c)
(.) f g arg = f (g arg)

If you're being really smart, you can doubly compose something, so that it takes two arguments before it's passed along:

((sum .) . map) double [1,2,3]

which reduces to:

(sum . map double) [1,2,3]

and finally:

sum (map double [1,2,3])
AJF
  • 11,767
  • 2
  • 37
  • 64