woljako
woljako

Reputation: 39

How to use foldl with operator

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

Answers (3)

nicodp
nicodp

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

chi
chi

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

mschmidt
mschmidt

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

Related Questions