Reputation: 22777
I am trying to create foldl
using foldr
(a good exercise to learn haskell, and the other SO answers seem to complex).
My solutions is this:
myFoldl :: (b -> a -> b) -> [a] -> (b -> b)
myFoldl f = foldr op z
where
z = []
op x xs b = myFoldl f xs (f b x)
but it does not work. I get an error saying:
• Couldn't match type ‘a -> b’ with ‘[a]’
Expected type: b -> (a -> b) -> a -> b
Actual type: b -> [a] -> a -> b
• In the first argument of ‘foldr’, namely ‘op’
In the expression: foldr op z
In an equation for ‘myFoldl’:
myFoldl f
= foldr op z
where
z = []
op x xs b = myFoldl f xs (f x b)
but it looks good to me. myFoldl
takes a function, a list, and something to work with. Why is this not working? (New to haskell, still trying to figure it all out).
Upvotes: 2
Views: 183
Reputation: 51119
Since you have:
myFoldl f = foldr op z
you must also have:
myFoldl f xs = foldr op z xs -- (**)
From the type of myFoldl
, the LHS must have type b -> b
. On the other hand, from the type of foldr
, the RHS has the same type as z
, which you defined as z = []
which has a list type, [c]
. So, this expression has type b -> b
but also the list type [c]
, and these two types cannot be reconciled.
The larger problem is that your op
shouldn't be defined recursively in terms of myFoldl
. The point of the fold (whether left or right) is to replace the explicit recursion, abstracting away the recursion pattern as the fold definition, expressing it with the one-step recombination operation op x r = ...
where r
is the result for our problem's recursive sub-problem, already calculated for us by the fold itself. A correct definition of the one-step recombination operation thus shouldn't involve any recursive definitions.
Sooooo, let me try to set you on the right track. I think you've recognized that the defining recursive relationship for your myFoldl
is:
myFoldl f (x:xs) b = myFoldl f xs (f b x) -- (1a)
myFoldl f [] b = b -- (1b)
Using the definition (**) above, you want to reconcile it with the defining recursive relationship for foldr
:
foldr op z (x:xs) = op x (foldr op z xs)
foldr op z [] = z
which we could eta abstract over b
like so:
foldr op z (x:xs) b = op x (foldr op z xs) b -- (2a)
foldr op z [] b = z b -- (2b)
Note that the only way (1b) and (2b) are going to give the same result is if b
and z b
are equal for all b
. Note that z
is a function here, not a list! Hopefully, you can immediately identify what function z
needs to be here.
For reconciling (1a) and (2a), your solution was to write op x xs b = myFoldl f xs (f b x)
, but that's not the right equation. The correct equation, matching up the RHSs of (1a) and (2a) above is:
op x (foldr op z xs) b = myFoldl f xs (f b x)
and rewriting the foldr
on the left in terms of our myFoldl
using (**) up above, we get:
op x (myFoldl f xs) b = myFoldl f xs (f b x)
Now, can you see what non-recursive definition of the one-step recombination operation op
would satisfy this equation? (Hint: it's a very simple definition.)
op x r b = ....
Upvotes: 4