Confusion about right folds in Haskell - haskell

Just for Background I am a Haskell and FP Beginner, self-learning.
I was going through folds on Learn You a Haskell for great good.
In this I came across this function
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x acc -> f x : acc) [] xs
Everything is good but as far as I understood the first parameter of the lambda x matches with [] and second acc matches with xs. Right? The confusion starts with the author saying that Then, we prepend it to the accumulator, which is was []. How is the second parameter acc matching with [] which is the first argument? Doesn't make sense.
But his implementation is working while mine (with [] and xs interchanged as parameters) is giving a big error
Practice.hs:88:41:
Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for map' :: (a -> b) -> [a] -> [b]
at Practice.hs:87:9
`b' is a rigid type variable bound by
the type signature for map' :: (a -> b) -> [a] -> [b]
at Practice.hs:87:9
Expected type: [b]
Actual type: [a]
In the second argument of `foldr', namely `xs'
In the expression: foldr (\ x acc -> f x : acc) xs []
In an equation for map':
map' f xs = foldr (\ x acc -> f x : acc) xs []
Failed, modules loaded: none.
What am I missing here? Does foldr use flip internally? Or did I just understood it all incorrectly?

The lambda is not applied to [] and xs. Instead it's the first argument to foldr. The second and third arguments to foldr are [] and xs respectively.

It helps to look at what the "symbolic" form of the fold functions looks like. If we have a list of arbitrary elements [b1, b2, b3, b4] and initial element a then:
foldr f a [b1, b2, b3, b4] = f b1 (f b2 (f b3 (f b4 a)))
Conversely the foldl would look like.
foldl f a [b1, b2, b3, b4] = f (f (f (f a b1) b2) b3) b4
This of course ignores the laziness component of the execution, but the general idea still holds.
In your function you fold a function of two arguments which pushes a an element transformed under f onto a cons list.
map' f xs = foldr (\x acc -> f x : acc) [] xs
Expanding this out where (xs=[x0,x1,...,xn]) like above yields:
map' f xs = (f x0 : (f x1 : (f x2 : ... (f xn : []))))
Where the ellipsis is just pseudocode for the all the elements in between. We see is just precisely the element wise map. Hope that helps build intuition.

Begin with the type of foldr, from Hoogle.
foldr :: (a -> b -> b) -> b -> [a] -> b
From this, it is apparent that the second argument of the lambda must match the second argument to foldr, i.e. acc matches [] and x is an element of xs, because the first argument of the lambda has type a, and the third argument of foldr has type [a].
Note that foldl and foldr have different signatures, and hence the arguments in the lambda are swapped.

Might be simplest to just look at the implementation of foldr:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
Then take a simple example like:
foldr (+) 0 [0, 1, 2, 4]
And follow exactly what happens as it recurses and generates the "spine".
Image of a foldr spine:
I'd recommend tracing what happens using pen and paper.

Yet another explanation, using long variable names for effect:
map :: (a -> b) -> [a] -> [b]
map f = foldr step []
where
-- If you have an incomplete solution to your problem, and the first
-- element of the input list, what is the last step you need to finish?
step elem incompleteSolution = f elem : incompleteSolution
The neat thing about using functions like foldr is that when you write your step function, the second argument to step will be the correct result for a smaller version of your problem.
One useful way to think of it is to imagine that foldr has already solved nearly all of your problem, but it's still missing the last step. For example, if you're trying to solve map f (x:xs), picture that foldr has already computed the solution for map f xs. Using that incomplete solution, f and x, what is the final step you need to perform to arrive at the complete solution? Well, as the code snippet illustrates, you apply f to x, and put that in front of the incomplete solution, and you're done.
The magic of foldr is that once you've figured out what to write for step, and what to use for the [] base case, then you're done. Your step function doesn't concern itself with the input list—all it can see is one input list element and an incomplete solution.

Related

Using Haskell's foldr

I'm learning Haskell and I've been wrestling with this problem:
Write func :: (a -> Bool) -> [a] -> [a] (take elements of a list until the predicate is false) using foldr
This is what I have so far:
func :: (a -> Bool) -> [a] -> [a]
func f li = foldr f True li
and got the following errors:
Couldn't match expected type ‘[a]’ with actual type ‘Bool’
and
Couldn't match type ‘Bool’ with ‘Bool -> Bool’
Expected type: a -> Bool -> Bool
Actual type: a -> Bool
I'm a bit confused since I learned foldr by passing a function with two arguments and getting a single value. For example I've used the function by calling
foldr (\x -> \y -> x*y*5) 1 [1,2,3,4,5]
to get a single value but not sure how it works when passing a single argument function into foldr and getting a list in return. Thank you very much.
Let’s do an easier case first, and write a function that uses foldr to do nothing (to break down the list and make a the same list). Let’s look at the type signature of foldr:
foldr :: (a -> b -> b) -> b -> [a] -> [b]
And we want to write an expression of the form
foldr ?1 ?2 :: [a] -> [a]
Now this tells us that (in the signature of foldr) we can replace b with [a].
A thing we haven’t worked out, ?2, is what we replace the end of the list with and it has type b = [a]. We don’t really have anything of type a so let’s just try the most stupid thing we can:
foldr ?1 []
And now the next missing thing: we have ?1 :: a -> [a] -> [a]. Let’s write a function for this. Now there are two reasonable things we can do with a list of things and another thing and nothing else:
Add it to the start
Add it to the end
I think 1 is more reasonable so let’s try that:
myFunc = foldr (\x xs -> x : xs) []
And now we can try it out:
> myFunc [1,2,3,4]
[1,2,3,4]
So what is the intuition for foldr here? Well one way to think of it is that the function passed gets put into your list instead of :, with the other item replacing [] so we get
foldr f x [1,2,3,4]
——>
foldr f x (1:(2:(3:(4:[]))))
——>
f 1 (f 2 (f 3 (f 4 x)))
So how can we do what we want (essentially implement takeWhile with foldr) by choosing our function carefully? Well there are two cases:
The predicate is true on the item being considered
The predicate is false for the item being considered
In case 1 we need to include our item in the list, and so we can try doing things like we did with our identity function above.
In case 2, we want to not include the item, and not include anything after it, so we can just return [].
Suppose our function does the right thing for the predicate "less than 3", here is how we might evaluate it:
f 1 (f 2 (f 3 (f 4 x)))
--T T F F (Result of predicate)
-- what f should become:
1 : (2 : ([] ))
——>
[1,2]
So all we need to do is implement f. Suppose the predicate is called p. Then:
f x xs = if p x then x : xs else []
And now we can write
func p = foldr f [] where
f x xs = if p x then x : xs else []

Converting a foldl into fold1

I am using the following fold to get the final monotonically decreasing sequence of a list.
foldl (\acc x -> if x<=(last acc) then acc ++ [x] else [x]) [(-1)] a
So [9,5,3,6,2,1] would return [6,2,1]
However, with foldl I needed to supply a start for the fold namely [(-1)]. I was trying to turn into to a foldl1 to be able to handle any range of integers as well as any Ord a like so:
foldl1 (\acc x -> if x<=(last acc) then acc ++ [x] else [x]) a
But I get there error:
cannot construct infinite type: a ~ [a]
in the second argument of (<=) namely last acc
I was under the impression that foldl1 was basically :
foldl (function) [head a] a
But I guess this isn't so? How would you go about making this fold generic for any Ord type?
I was under the impression that foldl1 was basically :
foldl (function) [head a] a
No, foldl1 is basically:
foldl function (head a) (tail a)
So the initial element is not a list of head a, but head a.
How would you go about making this fold generic for any Ord type?
Well a quick fix is:
foldl (\acc x -> if x<=(last acc) then acc ++ [x] else [x]) [head a] (tail a)
But there are still two problems:
in case a is an empty list, this function will error (while you probably want to return the empty list); and
the code is not terribly efficient since both last and (++) run in O(n).
The first problem can easily be addressed by using pattern matching to prevent that scenario. But for the latter you better would for instance use a reverse approach. Like for instance:
f :: Ord t => [t] -> [t]
f [] = [] -- case when the empty list is given
f a = reverse $ foldl (\acc#(ac:_) x -> if x <= ac then (x:acc) else [x]) [head a] (tail a)
Furthermore personally I am not a huge fan of if-then-else in functional programming, you can for instance define a helper function like:
f :: Ord t => [t] -> [t]
f [] = [] -- case when the empty list is given
f a = reverse $ foldl g [head a] (tail a)
where g acc#(ac:_) x | x <= ac = (x:acc)
| otherwise = [x]
Now reverse runs in O(n) but this is done only once. Furthermore the (:) construction runs in O(1) so all the actions in g run in O(1) (well given the comparison of course works efficient, etc.) making the algorithm itself O(n).
For your sample input it gives:
*Main> f [9,5,3,6,2,1]
[6,2,1]
The type of foldl1 is:
Foldable t => (a -> a -> a) -> t a -> a
Your function argument,
\acc x -> if x<=(last acc) then acc ++ [x] else [x]
has type:
(Ord a) => [a] -> a -> [a]
When Haskell's typechecker tries typechecking your function, it'll try unifying the type a -> a -> a (the type of the first argument of foldl1) with the type [a] -> a -> [a] (the type of your function).
To unify these types would require unifying a with [a], which would lead to the infinite type a ~ [a] ~ [[a]] ~ [[[a]]]... and so on.
The reason this works while using foldl is that the type of foldl is:
Foldable t => (b -> a -> b) -> b -> t a -> b
So [a] gets unified with b and a gets unified with the other a, leading to no problem at all.
foldl1 is limited in that it can only take functions which deal with only one type, or, in other terms, the accumulator needs to be the same type as the input list (for instance, when folding a list of Ints, foldl1 can only return an Int, while foldl can use arbitrary accumulators. So you can't do this using foldl1).
With regards to making this generic for all Ord values, one possible solution is to make a new typeclass for values which state their own "least-bound" value, which would then be used by your function. You can't make this function as it is generic on all Ord values because not all Ord values have sequence least bounds you can use.
class LowerBounded a where
lowerBound :: a
instance LowerBounded Int where
lowerBound = -1
finalDecreasingSequence :: (Ord a, LowerBounded a) => [a] -> [a]
finalDecreasingSequence = foldl buildSequence lowerBound
where buildSequence acc x
| x <= (last acc) = acc ++ [x]
| otherwise = [x]
You might also want to read a bit about how Haskell does its type inference, as it helps a lot in figuring out errors like the one you got.

Haskell- write map function using foldr

I am trying to write the map function using foldr. The problem is that when I ran this code :
> myMap f xs = foldr (\ acc x -> acc :(f x)) [] xs
I have the following problem:
No instance for (Num [a0]) arising from a use of 'it'
but when I run
myMap f xs = foldr (\x acc-> (f x):acc) [] xs
It works perfectly. Any ideas why?
the type of foldr is
foldr :: (a -> b -> b) -> b -> [a] -> b
therefore the binary operation that foldr uses to traverse and accumulate the list
has type (a -> b -> b),it first take an element of the list (type a)then the accumulator (type b) resulting in an expression of type b.
So, your first myMap function does not work becuase you are using "acc" and "x" in reverse order.
You want to apply f to x then append it to the acummulator of type b ( a list in this case)
The error you posted is not coming from your definition of myMap, it's coming from how you're using it. The type of the first myMap is ([a] -> [a]) -> [a] -> [a], which does not match the type of Prelude.map. In the second one you've swapped your variable names and also which one you're applying f to. The compiler doesn't care what you name the arguments in your lambda being passed to foldr, so foldr (\x acc -> f x : acc) is identical to foldr (\foo bar -> f foo : bar). That may be what's tripping you up here.
The second one works because (to put it simply) it's correct. In the first you're applying f to your accumulator list x (even though you have a variable named acc it's not your accumulator), so f must take a list and return a list. In the second you're applying f to each element, then prepending that to your accumulator list. If you had myMap (+1), it would have the type
myMap (+1) :: Num [a] => [a] -> [a]
Which says that you must pass it a list of values [a] where [a] implements Num, and currently there is no instance for Num [a], nor will there ever be.
TL;DR: In the first one you're applying your mapped function to your accumulator list, in the second one you're applying the mapped function to each element.

"Any function on finite lists that is defined by pairing the desired result with the argument list can always be redefined in terms of fold"

I was reading through the paper A tutorial on the universality and
expressiveness of fold, and am stuck on the section about generating tuples. After showing of how the normal definition of dropWhile cannot be defined in terms of fold, an example defining dropWhile using tuples was proved:
dropWhile :: (a -> Bool) -> [a] -> [a]
dropWhile p = fst . (dropWhilePair p)
dropWhilePair :: (a -> Bool) -> [a] -> ([a], [a])
dropWhilePair p = foldr f v
where
f x (ys,xs) = (if p x then ys else x : xs, x : xs)
v = ([], [])
The paper states:
In fact, this result is an instance of a
general theorem (Meertens, 1992) that states that any function on finite lists that is
defined by pairing the desired result with the argument list can always be redefined
in terms of fold, although not always in a way that does not make use of the original
(possibly recursive) definition for the function.
I looked at Meerten's Paper but do not have the background (category theory? type theory?) and did not quite find how this was proved.
Is there a relatively simple "proof" why this is the case? Or just a simple explanation as to why we can redefine all functions on finite lists in terms of fold if we pair the results with the original list.
Given the remark that you can / may need to use the original function inside, the claim as stated in your question seems trivial to me:
rewriteAsFold :: ([a] -> (b, [a])) -> [a] -> (b, [a])
rewriteAsFold g = foldr f v where
f x ~(ys,xs) = (fst (g (x:xs)), x:xs)
v = (fst (g []), [])
EDIT: Added the ~, after which it seems to work for infinite lists as well.

What's wrong with following foldl implementation?

By the task we've had to implement foldl by foldr. By comparing both function signatures and foldl implementation I came with the following solution:
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl _ acc [] = acc
myFoldl fn acc (x:xs) = foldr fn' (fn' x acc) xs
where
fn' = flip fn
Just flip function arguments to satisfy foldr expected types and mimic foldl definition by recursively applying passed function.
It was a surprise as my teacher rated this answer with zero points.
I even checked this definition stacks its intermediate results in the same way as the standard foldl:
> myFoldl (\a elm -> concat ["(",a,"+",elm,")"]) "" (map show [1..10])
> "((((((((((+1)+10)+9)+8)+7)+6)+5)+4)+3)+2)"
> foldl (\a elm -> concat ["(",a,"+",elm,")"]) "" (map show [1..10])
> "((((((((((+1)+10)+9)+8)+7)+6)+5)+4)+3)+2)"
The correct answer was the following defintion:
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl f z xs = foldr step id xs z
where step x g a = g (f a x)
Just asking why is my previous definition incorrect ?
Essentially, your fold goes in the wrong order. I think you didn't copy your output from foldl correctly; I get the following:
*Main> myFoldl (\ a elem -> concat ["(", a, "+", elem, ")"]) "" (map show [1..10])
"((((((((((+1)+10)+9)+8)+7)+6)+5)+4)+3)+2)"
*Main> foldl (\ a elem -> concat ["(", a, "+", elem, ")"]) "" (map show [1..10])
"((((((((((+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)"
so what happens is that your implementation gets the first element--the base case--correct but then uses foldr for the rest which results in everything else being processed backwards.
There are some nice pictures of the different orders the folds work in on the Haskell wiki:
This shows how foldr (:) [] should be the identity for lists and foldl (flip (:)) [] should reverse a list. In your case, all it does is put the first element at the end but leaves everything else in the same order. Here is exactly what I mean:
*Main> foldl (flip (:)) [] [1..10]
[10,9,8,7,6,5,4,3,2,1]
*Main> myFoldl (flip (:)) [] [1..10]
[2,3,4,5,6,7,8,9,10,1]
This brings us to a deeper and far more important point--even in Haskell, just because the types line up does not mean your code works. The Haskell type system is not omnipotent and there are often many--even an infinite number of--functions that satisfy any given type. As a degenerate example, even the following definition of myFoldl type-checks:
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl _ acc _ = acc
So you have to think about exactly what your function is doing even if the types match. Thinking about things like folds might be confusing for a while, but you'll get used to it.

Resources