Reputation: 1829
What represents [t0] -> a0 -> [a1]
in this error message? I just realized I must be applying (:)
to foldr
. Why is compiler not complaining that (*2)
expects something of kind *
as argument?
Prelude> foldr (:) . (* 2) [] [1..10]
<interactive>:141:19:
Couldn't match expected type `[t0] -> a0 -> [a1]'
with actual type `[a2]'
In the first argument of `* 2', namely `[]'
In the second argument of `(.)', namely `(* 2) [] [1 .. 10]'
In the expression: foldr (:) . (* 2) [] [1 .. 10]
Upvotes: 2
Views: 155
Reputation: 19637
We have
foldr (:) :: [a] -> ([a] -> [a])
(.) :: (c -> d ) -> (b -> c) -> (b -> d)
From this, we conclude that the second argument y
in the composition
foldr (:) . y
must result in a list, i.e., be of type
e -> [a]
In our case, y = (* 2) [] [1..10]
. So we have:
(* 2) [] [1..10] :: e -> [a] -- for some e and a
Thus:
(* 2) [] :: [f] -> e -> [a] -- for some e, a and f where (Num f, Enum f)
(The constraints on f
are because we use numeric literals and range notation in the
list [1..10]
.) Now, consider that 2
and (*)
are overloaded, and
(* 2) :: Num g => g -> g
From this we get that []
must have the same type as (* 2) []
(and that type must be an instance of Num
):
[] :: [f] -> e -> [a] -- for some e, a and f where
-- (Num f, Enum f, Num ([f] -> e -> [a]))
But this is not true, because []
has type [g]
for some g
. Now let's look at the
error message again:
Couldn't match expected type `[t0] -> a0 -> [a1]'
with actual type `[a2]'
In the first argument of `* 2', namely `[]'
So modulo renaming of type variables, this is exactly what the error message says.
The error points to `[]'
, so it's perhaps enlightening to see what the typechecker thinks should go in this position. In GHC 7.8, we'll be able to use the TypeHoles
extension for this, but for now, an easy way to do it is to abstract from []
, i.e., replace it by a function argument:
Prelude> :t \ x -> foldr (:) . (* 2) x [1..10]
\ x -> foldr (:) . (* 2) x [1..10]
:: (Enum t, Num ([t] -> a -> [a1]), Num t) =>
([t] -> a -> [a1]) -> a -> [a1] -> [a1]
From this, you can easily see that this term is actually still type-correct, it only
requires x
to be of the type
[t] -> a -> [a1]
with the additional class constraints (which are admittedly unlikely to hold).
Upvotes: 3
Reputation: 53891
So the type of foldr
is
foldr :: (a -> b -> b) -> b -> [a] -> b
So you're passing it (:)
so it's type becomes
foldr (:) :: [a] -> [a] -> [a]
However, you then try to compose it with (*2) [] [1..10]
. This isn't even well typed so you're in trouble. I think your problem here is that function application is the highest precedence of all.
foldr ((:) . (*2)) [] [1..10]
The explicit parens are necessary.
By the way, you can just use
map (*2) [1..10]
Upvotes: 8