Reputation: 39
I thought that two codes should run properly
foldr (:) [] [1..5]
foldl (:) [] [1..5]
But I get error use foldl:
Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [a] -> [a] -> [a]
Actual type: a -> [a] -> [a]
Relevant bindings include it :: [a] (bound at <interactive>:253:1)
In the first argument of ‘foldl’, namely ‘(:)’
In the expression: foldl (:) [] [1 .. 5]
Why foldl not run?
Upvotes: 1
Views: 486
Reputation: 2392
Let's start by its equations:
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl op z [] = z
foldl op z (x:xs) = foldl op (op z x) xs
The big difference between foldr
and foldl
is how the operator op
works: foldl
is tail recursive and applies the operator from left to right in contrast to foldr
which does the oppossite.
So, what you'd probably want is this:
foldl (\(currentFold, element) -> element:currentFold) [] [1,2,3,4,5]
Which could be beautified using flip
(as @mschmidt points out)
Recall that from foldr
equations:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr op z [] = z
foldr op z (x:xs) = op x (foldr op z xs)
it will be slightly different:
foldr (\(element, currentFold) -> element:currentFold) [] [1,2,3,4,5]
Which is the same as the one you posted:
foldr (:) [] [1,2,3,4,5]
Upvotes: 1
Reputation: 116174
Another way to understand it, is:
foldr (:) [] [1..5]
means
1 : (2 : (3 : (4 : (5 : []))))
while
foldl (:) [] [1..5]
means
(((([] : 1) : 2) : 3) : 4) : 5
The latter makes no sense: is uses numbers as if they were lists. Further, every usage of :
changes the type of the output ([]
is a list, []:x
is a list-of-lists, ([]:x):y
is a list-of-lists-of-lists, and so on).
Upvotes: 1
Reputation: 2800
The type signatures for foldl
and foldr
are slightly different in the function argument (they have switched arguments):
foldl :: (b -> a -> b) -> b -> t a -> b
foldr :: (a -> b -> b) -> b -> t a -> b
For foldl
to work you can use flip
which swaps the arguments of a function:
flip :: (a -> b -> c) -> b -> a -> c
I.e. this should work:
foldl (flip (:)) [] [1..5]
Upvotes: 4