Haskell - Group list elements with foldr function - list

This is for an assignment in Haskell.
We have been tasked with defining various functions using the foldr function.
We have been given a type:
group :: Eq a => [a] -> [[a]]
and been asked to define it such that:
group [1,2,2,3,4,4,4,5] = [[1], [2,2], [3], [4,4,4], [5]]
group [1,2,2,3,4,4,4,5,1,1,1] = [[1], [2,2], [3], [4,4,4], [5], [1,1,1]]
This is what I have so far:
group = foldr (\x xs -> if x == head (head xs) then (x : head xs) : xs else (x : []) : (head xs) : xs )
But when I try to load this into ghci interpreter I get the following error message:
Couldn't match type `[a0] -> [a]' with `[[a]]'
Expected type: [a] -> [[a]]
Actual type: [a] -> [a0] -> [a]
In the return type of a call of `foldr'
Probable cause: `foldr' is applied to too few arguments
In the expression:
foldr
(\ x xs
-> if x == head (head xs) then
(x : head xs) : xs
else
(x : []) : (head xs) : xs)
In an equation for `group':
group
= foldr
(\ x xs
-> if x == head (head xs) then
(x : head xs) : xs
else
(x : []) : (head xs) : xs)
If anyone could explain any reasons why my code isn't working as I expect it to, that would be greatly appreciated.
Thanks.

I think you are on the right track so I'll try to write your idea a bit nicer. What I want to say is this: you should pull out the first argument of foldr into an function and do pattern-matching again:
group :: Eq a => [a] -> [[a]]
group = foldr f undefined
where f x [] = undefined
f x (ys#(y:_):yss)
| x == y = undefined
| otherwise = undefined
this should do - now you only have to put in the right stuff where I put undefined :)
I'll come back later and finish it
well I guess you gave up or something - anyway here is one solution:
group :: Eq a => [a] -> [[a]]
group = foldr f []
where f x [] = [[x]]
f x (ys#(y:_):yss)
| x == y = (x:ys):yss
| otherwise = [x]:ys:yss
and a few examples:
λ> group []
[]
λ> group [1]
[[1]]
λ> group [1,1]
[[1,1]]
λ> group [1,2,1]
[[1],[2],[1]]
λ> group [1,2,2,3,4,4,4,5]
[[1],[2,2],[3],[4,4,4],[5]]
note that fs patterns are not exhaustive (which is no problem - think about why) - of course you can extent it if you want (and if you don't agree with group [] = [] than you have to.

Just to mention that if I am not wrong, this is the problem 9 from the 99 haskell problems that can be found here: https://wiki.haskell.org/99_questions/
For every problem, it has a bunch of solutions(usually) and since Carsten presented a great solution, you can go there and see other solutions so you can get different ideas on how the same thing can be achieved in various ways!

Related

How do I split a list on certain conditions in Haskell?

As a programming exercise I'm trying to build a function in Haskell where given a list it splits the list whenever an element is repeated. [1,2,3,3,4,5] would split into [[1,2,3],[3,4,5]] for example. My first idea was to split the list into a list of lists with single elements, where [1,2,3,3,4,5] would become [[1],[2],[3],[3],[4],[5]] and then merge lists only when the elements being compared are not equal, but implementing this has been a headache for me as I'm very new to Haskell and recursion has always given me trouble. I think something is wrong with the function I'm using to combine the lists, it will only ever return a list where all the elements that were broken apart are combined, where [1,2,3,3,4,5] becomes [[1],[2],[3],[3],[4],[5]] but my split_help function will transform this into [[1,2,3,3,4,5]] instead of [[1,2,3],[3,4,5]]
I've pasted my incomplete code below, it doesn't work right now but it should give the general idea of what I'm trying to accomplish. Any feedback on general Haskell code etiquette would also be welcome.
split_breaker breaks the list into a list of list and split_help is what I'm trying to use to combine unequal elements.
split_help x y
| x /= y = x ++ y
| otherwise = []
split_breaker :: Eq a => [a] -> [[a]]
split_breaker [] = []
split_breaker [x] = [[x]]
split_breaker (x:xs) = [x]:split_breaker xs
split_at_duplicate :: Eq a => [a] -> [[a]]
split_at_duplicate [x] = [[x]]
split_at_duplicate (x:xs) = foldl1 (split_help) (split_breaker [xs])
Do you want to work it something like this?
splitAtDup [1,2,3,3,3,4,4,5,5,5,5,6]
[[1,2,3],[3],[3,4],[4,5],[5],[5],[5,6]]
Am I right?
Then do it simple:
splitAtDup :: Eq a => [a] -> [[a]]
splitAtDup (x : y : xs) | x == y = [x] : splitAtDup (y : xs)
splitAtDup (x : xs) =
case splitAtDup xs of
x' : xs' -> (x : x') : xs'
_ -> [[x]]
splitAtDup [] = []
Here's a maximally lazy approach:
splitWhen :: (a -> a -> Bool) -> [a] -> [[a]]
splitWhen f = foldr go [[]] where
go x acc = (x:xs):xss where
xs:xss = case acc of
(z:_):_ | f x z -> []:acc
_ -> acc
splitAtDup :: Eq a => [a] -> [[a]]
splitAtDup = splitWhen (==)
To verify the laziness, try this:
take 2 $ take 4 <$> splitAtDup (1:2:3:3:4:5:6:undefined)
It can be fully evaluated to normal form as [[1,2,3],[3,4,5,6]].

How to get the Index of an element in a list, by not using "list comprehensions"?

I'm new in haskell programming and I try to solve a problem by/not using list comprehensions.
The Problem is to find the index of an element in a list and return a list of the indexes (where the elements in the list was found.)
I already solved the problem by using list comprehensions but now i have some problems to solve the problem without using list comprehensions.
On my recursive way:
I tried to zip a list of [0..(length list)] and the list as it self.
then if the element a equals an element in the list -> make a new list with the first element of the Tupel of the zipped list(my index) and after that search the function on a recursive way until the list is [].
That's my list comprehension (works):
positions :: Eq a => a -> [a] -> [Int]
positions a list = [x | (x,y) <- zip [0..(length list)] list, a == y]
That's my recursive way (not working):
positions' :: Eq a => a -> [a] -> [Int]
positions' _ [] = []
positions' a (x:xs) =
let ((n,m):ns) = zip [0..(length (x:xs))] (x:xs)
in if (a == m) then n:(positions' a xs)
else (positions' a xs)
*sorry I don't know how to highlight words
but ghci says:
*Main> positions' 2 [1,2,3,4,5,6,7,8,8,9,2]
[0,0]
and it should be like that (my list comprehension):
*Main> positions 2 [1,2,3,4,5,6,7,8,8,9,2]
[1,10]
Where is my mistake ?
The problem with your attempt is simply that when you say:
let ((n,m):ns) = zip [0..(length (x:xs))] (x:xs)
then n will always be 0. That's because you are matching (n,m) against the first element of zip [0..(length (x:xs))] (x:xs), which will necessarily always be (0,x).
That's not a problem in itself - but it does mean you have to handle the recursive step properly. The way you have it now, positions _ _, if non-empty, will always have 0 as its first element, because the only way you allow it to find a match is if it's at the head of the list, resulting in an index of 0. That means that your result will always be a list of the correct length, but with all elements 0 - as you're seeing.
The problem isn't with your recursion scheme though, it's to do with the fact that you're not modifying the result to account for the fact that you don't always want 0 added to the front of the result list. Since each recursive call just adds 1 to the index you want to find, all you need to do is map the increment function (+1) over the recursive result:
positions' :: Eq a => a -> [a] -> [Int]
positions' _ [] = []
positions' a (x:xs) =
let ((0,m):ns) = zip [0..(length (x:xs))] (x:xs)
in if (a == m) then 0:(map (+1) (positions' a xs))
else (map (+1) (positions' a xs))
(Note that I've changed your let to be explicit that n will always be 0 - I prefer to be explicit this way but this in itself doesn't change the output.) Since m is always bound to x and ns isn't used at all, we can elide the let, inlining the definition of m:
positions' :: Eq a => a -> [a] -> [Int]
positions' _ [] = []
positions' a (x:xs) =
if a == x
then 0 : map (+1) (positions' a xs)
else map (+1) (positions' a xs)
You could go on to factor out the repeated map (+1) (positions' a xs) if you wanted to.
Incidentally, you didn't need explicit recursion to avoid a list comprehension here. For one, list comprehensions are basically a replacement for uses of map and filter. I was going to write this out explicitly, but I see #WillemVanOnsem has given this as an answer so I will simply refer you to his answer.
Another way, although perhaps not acceptable if you were asked to implement this yourself, would be to just use the built-in elemIndices function, which does exactly what you are trying to implement here.
We can make use of a filter :: (a -> Bool) -> [a] -> [a] and map :: (a -> b) -> [a] -> [b] approach, like:
positions :: Eq a => a -> [a] -> [Int]
positions x = map fst . filter ((x ==) . snd) . zip [0..]
We thus first construct tuples of the form (i, yi), next we filter such that we only retain these tuples for which x == yi, and finally we fetch the first item of these tuples.
For example:
Prelude> positions 'o' "foobaraboof"
[1,2,8,9]
Your
let ((n,m):ns) = zip [0..(length (x:xs))] (x:xs)
is equivalent to
== {- by laziness -}
let ((n,m):ns) = zip [0..] (x:xs)
== {- by definition of zip -}
let ((n,m):ns) = (0,x) : zip [1..] xs
== {- by pattern matching -}
let {(n,m) = (0,x)
; ns = zip [1..] xs }
== {- by pattern matching -}
let { n = 0
; m = x
; ns = zip [1..] xs }
but you never reference ns! So we don't need its binding at all:
positions' a (x:xs) =
let { n = 0 ; m = x } in
if (a == m) then n : (positions' a xs)
else (positions' a xs)
and so, by substitution, you actually have
positions' :: Eq a => a -> [a] -> [Int]
positions' _ [] = []
positions' a (x:xs) =
if (a == x) then 0 : (positions' a xs) -- NB: 0
else (positions' a xs)
And this is why all you ever produce are 0s. But you want to produce the correct index: 0, 1, 2, 3, ....
First, let's tweak your code a little bit further into
positions' :: Eq a => a -> [a] -> [Int]
positions' a = go xs
where
go [] = []
go (x:xs) | a == x = 0 : go xs -- NB: 0
| otherwise = go xs
This is known as a worker/wrapper transform. go is a worker, positions' is a wrapper. There's no need to pass a around from call to call, it doesn't change, and we have access to it anyway. It is in the enclosing scope with respect to the inner function, go. We've also used guards instead of the more verbose and less visually apparent if ... then ... else.
Now we just need to use something -- the correct index value -- instead of 0.
To use it, we must have it first. What is it? It starts as 0, then it is incremented on each step along the input list.
When do we make a step along the input list? At the recursive call:
positions' :: Eq a => a -> [a] -> [Int]
positions' a = go xs 0
where
go [] _ = []
go (x:xs) i | a == x = 0 : go xs (i+1) -- NB: 0
| otherwise = go xs (i+1)
_ as a pattern means we don't care about the argument's value -- it's there but we're not going to use it.
Now all that's left for us to do is to use that i in place of that 0.

Grouping consecutive duplicates in a list?

Very basic but I'm finding the problem frustrating. I'm trying to group consecutive elements of a list:
myList = [1,2,3,4,4,4,5]
becomes
myList = [[1],[2],[3],[4,4,4],[5]]
This is my attempt using foldr with an accumulator:
print $ foldr (\ el acc -> if el /= head (head acc) then el ++ (head acc) else acc) [['a']] myList
I don't understand why I'm getting the following error:
Couldn't match expected type ‘[a0]’ with actual type ‘Int’
In the expression: 'a'
In the expression: ['a']
In the second argument of ‘foldr’, namely ‘[['a']]’
Any advice would be great!
Writing a fold on lists requires us to answer just two cases: [] (the empty list, or "nil") and x:xs (an element followed by a list, or "cons").
What is the answer when the list is empty? Lets say the answer is also an empty list. Therefore:
nilCase = []
What is the answer when the list is not empty? It depends on what we have already accumulated. Lets say we have already accumulated a group. We know that groups are non-empty.
consCase x ((g11:_):gs)
If x == g11 then we add it to the group. Otherwise we begin a new group. Therefore:
consCase x ggs#(g1#(g11:_):gs)
| x == g11 = (x:g1):gs
| otherwise = [x]:ggs
What if we have not accumulated any groups yet? Then we just create a new group.
consCase x [] = [[x]]
We can consolidate the three cases down to two:
consCase x ggs
| g1#(g11:_):gs <- ggs, x == g11 = (x:g1):gs
| otherwise = [x]:ggs
Then the desired fold is simply:
foldr consCase nilCase
Using foldr, it should be:
group :: (Eq a) => [a] -> [[a]]
group = foldr (\x acc -> if head acc == [] || head (head acc) == x then (x:head acc) : tail acc else [x] : acc) [[]]
The type of your case case is [[Char]], you are attempting to build a value of type [[Int]]. Our base case should be an empty list, and we'll add list elements in each step.
Let's look at the anonymous function you're written next. Note that we'll fail due to type based on your current if within the accumulator (they must return values of the same type, and the same type as the accumulator. It'll be better, and cleaner, if we pattern match the accumulator and apply the function differently in each case:
func :: Eq a => [a] -> [[a]]
func = foldr f []
where f x [] = undefined
f x (b#(b1:_):bs)
| x == b1 = undefined
| otherwise = undefined
When we encounter the base case, we should just add the our element wrapped in a list:
f x [] = [[x]]
Next, we'll deal with the non-empty list. If x is equal to the next head of the head of the list, we should add it to that list. Otherwise, we shou
f x (b#(b1:_):bs)
| == b1 = (x:b):bs
| = [x]:b:bs
Putting this together, we have:
func :: Eq a => [a] -> [[a]]
func = foldr f []
where f x [] = [[x]]
f x (b#(b1:_):bs)
| x == b1 = (x:b):bs
| otherwise = [x]:b:bs
Having broken the problem down, it's much easier to rewrite this more compactly with a lambda function. Notice that the head [[]] is just [], so we can handle the empty list case and the equality case as one action. Thus, we can rewrite:
func :: (Eq a) => [a] -> [[a]]
func = foldr (\x (b:bs) -> if b == [] || x == head b then (x:b):bs else [x]:b:bs) [[]]
However, this solution ends up requiring the use of head since we must pattern match all versions of the accumulator.

Taking out the last occurrence of a certain element in a list in Haskell

I'm having trouble writing this function that takes a predicate and a list of integers, then eliminates the last occurrence of the integer that satisfies the predicate in the list. I was able to take out the first occurrence of the predicate in the list with my function below:
fun :: (Int -> Bool) -> [Int] -> [Int]
fun check (s:ss)
|check s = ss
|otherwise = s : fun check ss
What I need help on is how I should modify this function to take out the last occurrence of the integer, instead of the first. For example, fun (<2) [3,4,1,5,0,-3,9] would return [3,4,1,5,0,9].
(I couldn't use where due to some indentation problems)
removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p xs =
let
go c [] = tail (c [])
go c (x:xs)
| p x = c (go (x:) xs)
| otherwise = go (c . (x:)) xs
in case break p xs of
(ok, []) -> ok
(ok, x:xs) -> ok ++ go (x:) xs
go collects elements for which the predicate doesn't hold in a difference list and prepends this list to the result once a new satisfying the predicate element is found. Pattern matching on break p xs ensures that difference lists always start with an element that satisfies the predicate and we can drop it if it's the last.
Works with infinite lists:
main = do
print $ removeLast (< 2) [3,4,1,5,0,-3,9] -- [3,4,1,5,0,9]
print $ removeLast (== 2) [1,3] -- [1,3]
print $ take 10 $ removeLast (< 2) (cycle [1,3]) -- [1,3,1,3,1,3,1,3,1,3]
Here is an obfuscated version:
removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p xs = case break p xs of
(ok, []) -> ok
(ok, x:xs) -> ok ++ foldr step (tail . ($[])) xs (x:) where
step x r c = if p x then c (r (x:)) else r (c . (x:))
If you want to have fun with it, try this version.
removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p = fst . foldr go ([], False) where
go x ~(r, more)
| p x = (if more then x : r else r, True)
| otherwise = (x : r, more)
This seems to be almost as lazy as it can be, and it gets to the point pretty quickly. It could produce the list spine more lazily with some effort, but it produces list elements maximally lazily.
After some more thought, I realize that there is some tension between different aspects of laziness in this case. Consider
removeLast p (x : xs)
There are two ways we can try to find out whether to produce a [] or (:) constructor.
We can check xs; if xs is not [], then we can produce (:).
We can check p x. If p x is False, then we can produce (:).
These are the only ways to do it, and their strictness is not comparable. The only "maximally lazy" approach would be to use parallelism to try it both ways, which is not the most practical approach.
How about this:
fun :: (Num a) => (a -> Bool) -> [a] -> [a]
fun check (s:ss)
|check s = ss
|otherwise = s : fun check ss
Then, apply your fun function like this:
reverse $ fun (\ x -> x `mod` 3 == 0) (reverse [1..10])
HTH

Apply a function to every second element in a list

I'd like to apply a function to every second element in a list:
> mapToEverySecond (*2) [1..10]
[1,4,3,8,5,12,7,16,9,20]
I've written the following function:
mapToEverySecond :: (a -> a) -> [a] -> [a]
mapToEverySecond f l = map (\(i,x) -> if odd i then f x else x) $ zip [0..] l
This works, but I wonder if there is a more idiomatic way to do things like that.
I haven't written very much Haskell, but here's the first thing that came into mind:
func :: (a -> a) -> [a] -> [a]
func f [] = []
func f [x] = [x]
func f (x:s:xs) = x:(f s):(func f xs)
It is a little ulgy, since you have to not only take care of the empty list, but also the list with one element. This doesn't really scale well either (what if you want every third, or
One could do as #Landei points out, and write
func :: (a -> a) -> [a] -> [a]
func f (x:s:xs) = x:(f s):(func f xs)
func f xs = xs
In order to get rid of the ugly checks for both [] and [x], though, IMHO, this makes it a little harder to read (at least the first time).
Here is how I would do it:
mapOnlyOddNumbered f [] = []
mapOnlyOddNumbered f (x:xs) = f x : mapOnlyEvenNumbered f xs
mapOnlyEvenNumbered f [] = []
mapOnlyEvenNumbered f (x:xs) = x : mapOnlyOddNumbered f xs
Whether this is "idiomatic" is a matter of opinion (and I would have given it as a comment if it would fit there) , but it may be useful to see a number of different approaches. Your solution is just as valid as mine, or the ones in the comments, and easier to change into say mapOnlyEvery13nd or mapOnlyPrimeNumbered
mapToEverySecond = zipWith ($) (cycle [id, (*2)])
Is the smallest I can think of, also looks pretty clear in my opinion. It also kinda scales with every nth.
Edit: Oh, people already suggested it in comments. I don't want to steal it, but I really think this is the answer.
Here's how I would probably do it:
mapToEverySecond f xs = foldr go (`seq` []) xs False
where
go x cont !mapThisTime =
(if mapThisTime then f x else x) : cont (not mapThisTime)
But if I were writing library code, I'd probably wrap that up in a build form.
Edit
Yes, this can also be done using mapAccumL or traverse.
import Control.Applicative
import Control.Monad.Trans.State.Strict
import Data.Traversable (Traversable (traverse), mapAccumL)
mapToEverySecond :: Traversable t => (a -> a) -> t a -> t a
-- Either
mapToEverySecond f = snd . flip mapAccumL False
(\mapThisTime x ->
if mapThisTime
then (False, f x)
else (True, x))
-- or
mapToEverySecond f xs = evalState (traverse step xs) False
where
step x = do
mapThisTime <- get
put (not mapThisTime)
if mapThisTime then return (f x) else return x
Or you can do it with scanl, which I'll leave for you to figure out.
This is more a comment to #MartinHaTh's answer. I'd slightly optimize his solution to
func :: (a -> a) -> [a] -> [a]
func f = loop
where
loop [] = []
loop [x] = [x]
loop (x:s:xs) = x : f s : loop xs
Not very elegant, but this is my take:
mapToEverySecond f = reverse . fst . foldl' cmb ([], False) where
cmb (xs, b) x = ((if b then f else id) x : xs, not b)
Or improving on MartinHaTh's answer:
mapToEverySecond f (x : x' : xs) = x : f x' : mapToEverySecond f xs
mapToEverySecond _ xs = xs