Reputation: 61041
Reading "Real World Haskell", on page 95 the author provides an example:
myFoldl f z xs = foldr step id xs z
where step x g a = g (f a x)
My question is: Why does this code compile? foldr
takes only three arguments - but here, it is passed four: step
, id
, xs
, z
.
For example, this doesn't work (because sum expects one):
sum filter odd [1,2,3]
instead I must write:
sum $ filter odd [1,2,3]
Upvotes: 9
Views: 277
Reputation: 53665
foldr
only takes 3 arguments
Wrong. All functions in Haskell take exactly 1 argument, and produce exactly 1 result.
foldr :: (a -> b -> b) -> b -> [a] -> b
See, foldr
takes one argument (a -> b -> b)
, and produces 1 result: b -> [a] -> b
. When you see this:
foldr step id xs z
Remember, it is just shorthand for this:
((((foldr step) id) xs) z)
This explains why this is nonsense:
sum filter odd [1,2,3]
(((sum filter) odd) [1,2,3])
sum :: Num a => [a] -> a
takes a list as its input, but you gave it a function.
Upvotes: 9
Reputation: 49085
Here's the type of foldr
:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Can we figure out how it becomes a four-argument function? Let's give it a try!
we're giving it id :: d -> d
as the second parameter (b
), so let's substitute that into the type:
(a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d)
in Haskell, a -> a -> a
is the same as a -> (a -> a)
, which gives us (removing the last set of parentheses):
(a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d
let's simplify, by substituting e
for (a -> (d -> d) -> (d -> d))
and f
for (d -> d
), to make it easier to read:
e -> f -> [a] -> d -> d
So we can plainly see that we've constructed a four-argument function! My head hurts.
Here's a simpler example of creating an n + 1-argument function from an n-arg func:
Prelude> :t id
id :: a -> a
id
is a function of one argument.
Prelude> id id id id id 5
5
But I just gave it 5 args!
Upvotes: 12
Reputation: 152707
It's because of how polymorphic foldr
is:
foldr :: (a -> b -> b) -> b -> [a] -> b
Here, we've instantiated b
to a function type, let's call it c -> c
, so the type of foldr
specializes to (for example)
foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c
Upvotes: 10