Well, let's take a look at the type signature for the curried function foldr
:
>:t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
So foldr
takes a binary function (i.e. a->b->b
), a b
value, a list of a
values, and returns a b
value.
Let's also look at the documentation for foldr
to get a more clear definition:
foldr, applied to a binary operator, a starting value (typically the
right-identity of the operator), and a list, reduces the list using
the binary operator, from right to left:
Now, let's take a look at the type signature for myConcat xs = foldr (++) []
> :t myConcat
myConcat :: t -> [[a]] -> [a]
Hmm...that's not what we wanted...
The problem is that you never provided foldr
a value of type [a]
. So now, myConcat
needs some value, of any type, to satisfy xs
and a value of type [a]
to complete foldr (++) []
, like:
> myConcat 2 [[1,2],[3,4]]
[1,2,3,4]
> myConcat Nothing [[1,2],[3,4]]
[1,2,3,4]
That works, but the first argument is just a waste.
However, if we pass that xs
value over to foldr (++) []
, like:
myConcat xs = foldr (++) [] xs
and check its type signature
> :t myConcat
myConcat :: [[a]] -> [a]
Ah, much better. Now myConcat uses xs
to complete the foldr
function.
Also, myConcat = foldr (++) []
also works, and is actually an example of point-free style programming. If we check the type signature of foldr (++) []
,
> :t foldr (++) []
foldr (++) [] :: [[a]] -> [a]
Since we already provided foldr
its first two arguments through partial application, we get a function back that will takes a [[a]]
value and do what we want! So we just assign it to a name, and it works just like the example above, but we didn't need to explicitly pass arguments!
> let myConcat = foldr (++) []
> :t myConcat
myConcat :: [[a]] -> [a]
> myConcat [[1,2],[3,4]]
[1,2,3,4]