Length with foldl and foldr - haskell

I have two functions computing the length of a list of integers
lengthFoldl :: [Int] -> Int
lengthFoldl xs = (foldl (\_ y -> y+1) 0 xs)
and
lengthFold :: [a] -> Int
lengthFold xs = foldr (\_ y -> y+1) 0 xs
they are the same except one uses foldr and one foldl.
But when trying to compute the length of any list [1 .. n] I get a wrong result (one too big) from lengthFoldl.

To complement joelfischerr's answer, I'd like to point out that a hint is given by the types of your functions.
lengthFoldl :: [Int] -> Int
lengthFold :: [a] -> Int
Why are they different? I guess you might had to change the first one to take an [Int] since with [a] it did not compile. This is however a big warning sign!
If it is indeed computing the length, why should lengthFoldl care about what is the type of the list elements? Why do we need the elements to be Ints? There is only one possible explanation for Int being needed: looking at the code
lengthFoldl xs = foldl (\_ y -> y+1) 0 xs
we can see that the only numeric variable here is y. If y is forced to be a number, and list elements are also forced to be numbers, it seems as if y is taken to be a list element!
And indeed that is the case: foldl passes to the function the accumulator first, the list element second, unlike foldr.
The general thumb rule is: when type and code do not agree, one should think carefully about which one is right. I'd say that most Haskellers would think that, in most cases, it is easier to get the type right than the code right. So, one should not just adapt the type to the code to force it to compile: a type error can instead witness a bug in the code.

Looking at the type definitions of foldl and foldr it becomes clear what the issue is.
:t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
and
:t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
One can see that the foldr takes the item of the list and the second argument into the function and foldl takes the second argument and the item of the list into the function.
Changing lengthFoldl to this solves the problem
lengthFoldl :: [Int] -> Int
lengthFoldl xs = foldl (\y _ -> y+1) 0 xs
Edit: Using foldl instead of foldl' is a bad idea: https://wiki.haskell.org/Foldr_Foldl_Foldl'

Related

Why doesn't this function work if I use "[xs]" instead of "xs"?

split :: [a] -> Int -> ([a], [a])
split [xs] n =
(take n [xs], drop n [xs])
The same code works if I give the variable as xs instead of [xs], signatures are same in both cases. Using [xs] gives the error that pattern is non-exhaustive. I understand it's telling that the input I gave is not covered by my code, but not clear what is happening under the hood.
Test input: [1,2,3] 2.
Somehow a lot of people think that [xs] as pattern means that you unify a list with xs. But this is incorrect, since the function signature (either derived implicitly, or stated explicitly) already will prevent you to write code where you call the function with a non-list item.
A list has two constructors:
the empty list []; and
the "cons" (h : t) with h the head (first element), and t the tail (a list with the remaining elements).
Haskell however introduces some syntactical sugar as well. For example [1] is short for (1:[]), and [1, 4, 2] for (1:(4:(2:[]))).
So that means that if you write [xs], behind the curtains you defined a pattern (xs: []) which thus means you match all lists with exactly one element, and that single element (not the entire list) is then xs.
Anyway, the solution is to use:
split xs n = (take n xs, drop n xs)
Since both take :: Int -> [a] -> [a] and drop :: Int -> [a] -> [a] have in the signature that xs is supposed to be a list, Haskell will derive automatically that n is supposed to be an Int, and xs an [a].
Note that you can use splitAt :: Int -> [a] -> ([a], [a]) as well. We can make the signature equivalent to the one you target with:
split = flip splitAt

Haskell:Non-exhaustive patterns in function bean [duplicate]

split :: [a] -> Int -> ([a], [a])
split [xs] n =
(take n [xs], drop n [xs])
The same code works if I give the variable as xs instead of [xs], signatures are same in both cases. Using [xs] gives the error that pattern is non-exhaustive. I understand it's telling that the input I gave is not covered by my code, but not clear what is happening under the hood.
Test input: [1,2,3] 2.
Somehow a lot of people think that [xs] as pattern means that you unify a list with xs. But this is incorrect, since the function signature (either derived implicitly, or stated explicitly) already will prevent you to write code where you call the function with a non-list item.
A list has two constructors:
the empty list []; and
the "cons" (h : t) with h the head (first element), and t the tail (a list with the remaining elements).
Haskell however introduces some syntactical sugar as well. For example [1] is short for (1:[]), and [1, 4, 2] for (1:(4:(2:[]))).
So that means that if you write [xs], behind the curtains you defined a pattern (xs: []) which thus means you match all lists with exactly one element, and that single element (not the entire list) is then xs.
Anyway, the solution is to use:
split xs n = (take n xs, drop n xs)
Since both take :: Int -> [a] -> [a] and drop :: Int -> [a] -> [a] have in the signature that xs is supposed to be a list, Haskell will derive automatically that n is supposed to be an Int, and xs an [a].
Note that you can use splitAt :: Int -> [a] -> ([a], [a]) as well. We can make the signature equivalent to the one you target with:
split = flip splitAt

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 Polymorphic definition

I am unable to understand the difference between fold and foldr.
The definition of fold is:
fold :: (t->t->t) -> [t] -> t
fold f [a] = a
fold f (a:b:x)= f a (fold f (b:x))
where there is only one type-parameter t
foldr is defined as
foldr :: (t->u->u) -> u -> [t] -> u
foldr f s [] = s
foldr f s (a:x) = f a (foldr f s x)
I am reading "The craft of functional programming" and it says the fold function is modified by adding an extra argument for the purpose of checking for empty list. This doesn't make sense why there was a need for foldr when the fold function itself could have been modified to serve all the purposes.
Secondly,when I tried the following example from the book:
rev :: [t] -> [t]
rev list = foldr stick [] list
stick :: t -> [t] -> [t]
stick a x = x++[a]
and modified the definition of foldr to foldr::(t->t->t)->[t]->t. Hugs threw an error of inifinite unification type. I tried googling but could not find a satisfactory answer.
so to sum up my doubts are as follows:
doubt1: The reason for making the foldr types to be more general than fold.
doubt2: why do i get an error namely infinitely unification type.
I'll start at the end:
rev :: [t] -> [t]
rev list = foldr stick [] list
stick :: t -> [t] -> [t]
stick a x = x ++ [a]
will work just fine if you use the definition of foldr you gave:
foldr :: (t->u->u) -> u -> [t] -> u
foldr f s [] = s
foldr f s (a:x) = f a (foldr f s x)
as you can see here:
λ> rev [1..5]
[5,4,3,2,1]
what will not work is if you replace it with your definition of fold:
fold :: (t->t->t) -> [t] -> t
no matter how you name it because the trouble start with the signature.
See - when you do rev list = fold stick [] list then you say that
t -> t -> t
should somehow be equal to
t' -> [t'] -> [t']
as the first one is the type fold expects for it's first argument and the second is the signature given by stick (renamed t to t' here to indicate that the types should could be different).
Now this would mean that both t ~ t' and t ~ [t'] or t ~ [t] which is most likely the error you get (btw: a ~ b here is me saying two types a and b should be equal - think = if you like)
This should shed some light on your doubt2 I hope
now to the first part: To be honest I have no clue what I should tell you.
The reason to make fold more general is that then it's more general - indeed foldr is a very special function for lists - it is the list catamorphism (see also wikipedia)
But that's just complicated for general function to operate on lists
Indeed you can rewrite a huge number of functions on list (basically the recursive ones using patter-matching in the empty or cons style) with just foldr - and this will very likely be a big part of your course (I think you are a student of FP101x right?) and of your book - as it's the example for higher-order-functions to rule them all ;)

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.

Resources