Related
Given list, break it into lists of identical items next to each other:
[1,1,2,4,5,5] ⟼ [[1,1], [2], [4], [5,5]].
And i need to do that using recursion and without higher order functions.
Here what i've got so far
breakList :: [Int] -> [[Int]]
breakList [] = [[]]
breakList [x] = [[x]]
breakList (x:y:rest)
| x == y = [x] : breakList (y:rest)
| otherwise = [x] : breakList rest
but it does not work.
You can check if the first item of the result of the recursive call has the same value. If that is the case, we prepend that list with x, otherwise we start a "new group" with x as only member of a list, so [x]:
breakList :: Eq a => [a] -> [[a]]
breakList [] = []
breakList [x] = [[x]] -- (1)
breakList (x:xs) -- (2)
| x == y = (x:ys) : yss -- (3)
| otherwise = [x] : ys : yss -- (4)
where ~(ys#(y:_):yss) = breakList xs -- (5)
here we thus first calculate the result of the tail recursion, we know that this will be non-empty since the (x:xs) pattern in (2) will only fire if the list contains at least two items (if it contains only one item, then the (1) clause will fire.
We then can pattern match the result with the pattern ~(ys#(y:_):yss) where ys is the first sublist of the result, y is the first item of that sublist, and yss is a, possibly empty, list of other groups that have been constructed.
We thus can check if the item x we have to put in a group has the same value as the first item y of the first subgroup. If that is the case we use (x:ys) : yss to construct a new lsit where we prepend the first sublist with x (2); if that is not the case, we prepend the sublists with a list [x] to create a new group.
We can make it more lazy with:
breakList :: Eq a => [a] -> [[a]]
breakList [] = []
breakList [x] = [[x]] -- (1)
breakList (x:xs#(y:_)) -- (2)
| x == y = (x:ys) : yss -- (3)
| otherwise = [x] : ys : yss -- (4)
where ~(ys:yss) = breakList xs -- (5)
This can also work on an infinite list with each time the same object: breakList (1 : 1 : 2 : 4 : 5: 5 : repeat 1)) will produce [[1,1],[2],[4],[5,5],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, …
Here is an alternative solution which uses a list as auxiliary data structure during the traversal of the list.
This auxiliary data structure stores the equal element up to now. For each new element (1) we check if it is equal to one of the elements in the auxiliary list, if it is we add it to that list, otherwise (2) we output the auxiliary list as a result and start a new auxiliary list with this new element. At the end (3) we simply output the auxiliary list we have got up to now as the final result.
breakList :: [Int] -> [[Int]]
breakList [] = []
breakList (x:xs) = go [x] xs where
go ys [] = [ys] -- (3)
go ~ys#(y:_) (x:xs)
| x == y = go (x:ys) xs -- (1)
| otherwise = ys : go [x] xs -- (2)
If you want it to be stable, i.e. all elements must stay in the same order (in the case of integers this does not matter, but it could for other data types), then you have to reverse the output lists:
breakList :: [Int] -> [[Int]]
breakList [] = []
breakList (x:xs) = go [x] xs where
go ys [] = [reverse ys]
go ~ys#(y:_) (x:xs)
| x == y = go (x:ys) xs
| otherwise = reverse ys : go [x] xs
This algorithm also assumes that == is transitive, which is not technically necessary, but certainly the case for integers. Although, the specification you've given is ambiguous if == is not transitive, which element should we compare each new element to? The first element of the group, or the previous element? Anyway, it is probably not something you have to worry about.
This is what group already does. :) Apparently, it is very unassumingly defined as an equivalent of group (x:xs) = (x:ys) : group zs where (ys,zs) = span (x ==) xs.
Of course you're forbidden the use of HOFs, so will need to inline the definition of span. And it must be lazy enough, i.e. produce as much as possible as early as possible, forcing as little as possible of its input.
Something like
breakList :: [Int] -> [[Int]]
breakList [] = [[]]
breakList (x:ys) = (x:xs):r
where
(xs:r) = go x ys
go x (y:ys)
| x==y = ((y:a):b)
| otherwise = [] : ((y:a):b)
where (a:b) = go y ys
go _ [] = [[]]
So that we have
> breakList $ [1,1,1,2,3,3,4]
[[1,1,1],[2],[3,3],[4]]
> take 1 . head . breakList $ repeat 1
[1]
> take 3 . head . breakList $ [1,1,1]++undefined
[1,1,1]
Seems to be properly lazy indeed.
I'm trying to write this pattern matching recursion expression
let rec drop_last l =
match l with
| [] -> []
| [_] -> []
| h::t -> h :: drop_last t ;;
as an 'if statement' recursion expression.
I've started doing the following :
let rec drop_last2 l =
if l = [] then [] else
if l = [_] then [] else
l = List.hd::List.tl then List.hd::drop_last2 (List.tl l);;
However, I'm getting a syntax error from the compiler. Could someone please tell me how should I modify this if statement into something correct?
As Jeffrey said, [_] is a pattern not a value, you can't compare to it.
and in l = List.hd::List.tl first of all it's incorrect, List.hd is a function that takes a list and returns it's it's head, List.tl is also a function that takes a list but this one returns it's tail, and the constructor _::_ takes a value and a list of values of the same type. So you should really check the documentation (https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html) for more information on how to use functions and costructors.
to go from this:
let rec drop_last l =
match l with
| [] -> []
| [_] -> []
| h::t -> h :: drop_last t ;;
to an if-statement, you can do it this way:
let rec drop_last l =
if List.length l <= 1
then []
else List.hd l :: drop_last (List.tl l) ;;
That is because the pattern [] checks if the list is empty, so it can be replaced by List.length l = 0 and [_] checks if the list has one element, so it can be replaced by List.length l = 1 and since in both those cases you return [], you can join them with List.length l <= 1 and List.hd requires an argument that list a list, so it needs to be applied to l to give you the head, then appended to the recursive call with the tail to create a new list to be returned.
The construct [_] is a pattern, not a value. So you can't use = to compare it to a value as you are trying to do.
The thing to do, I believe, is to concentrate on thinking about the length of the list. The pattern [] matches when the length is 0 and the pattern [_] matches when the length is 1. You can use these facts in your if statements.
I'm new to Haskell and are playing around a bit. I created a recursive function with guards. See function below:
filterAge :: [Person] -> [String]
filterAge (x:xs)
| (x:xs) == [] = []
| (getAge x) < 30 || (getAge x) > 40 = [] ++ filterAge xs
| otherwise = [getName x] ++ filterAge xs
I have a data set created with 10 Persons which I use in this method. When I tried this function it gave all the right people, but after that it got a Non-exhaustive patterns error:
["Lise","Jaap","Elle","Ebba"*** Exception: D:\...:(44,1)-(47,77): Non-exhaustive patterns in function filterAge
I found out that it never reaches the first guard. So I played around a bit and found out something really strange (in my opinion):
*Main> let (x:xs) = []
*Main> (x:xs) == []
False
Now my main question is: Why does (x:xs) == [] return False?
If anyone has a better way for me of doing the function that'd be great, but it's not very important.
Thanks in advance!
EDIT
Thanks to Willem Van Onsem and Lambda.xy.x I got a quick answer to my question. This resulted in the following function which works perfectly:
filterAge :: [Person] -> [String]
filterAge [] = []
filterAge (x:xs)
| (getAge x) < 30 || (getAge x) > 40 = [] ++ filterAge xs
| otherwise = [getName x] ++ filterAge xs
But for the best version you'd have to check the answer of Willem Van Onsem.
A list is defined as:
data [] a = [] | a : [a]
So there are two constructors for a list: [] the empty list, and (x:xs) a constructor with one element, and a tail that can store an arbitrary number (zero or more) remaining elements.
Therefore (x:xs) is a list with at least one element: the x. The xs can be an empty list (since it has type [a]), but x has type a so that is the "head" of the list. Your let statement works with pattern matching, and since the empty list cannot match with (x:xs), it will always fail.
Another implication is that your first guard can never fire. In order to fix the issue, you should implement a separate case for the empty list. Like:
filterAge :: [Person] -> [String]
filterAge [] = [] -- empty list case
filterAge (x:xs) -- first guard dropped
| (getAge x) < 30 || (getAge x) > 40 = [] ++ filterAge xs
| otherwise = [getName x] ++ filterAge xs
Note that we dropped the first guard in the second clause, since we know that will always fail, and thus checking this will (potentially) only cost CPU cycles.
There are still some parts we can optimize:
we call getAge twice, which is useless, we can use a where clause to optimize this;
[] ++ somelist is simply somelist: appending after an empty list results in that list; and
[element] ++ somelist is element : somelist, since now we work with the list constructor directly.
So our filterAge can be rewritten into:
filterAge :: [Person] -> [String]
filterAge [] = [] -- empty list case
filterAge (x:xs) | age < 30 || age > 40 = filterAge xs
| otherwise = getName x : filterAge xs
where age = getAge x
Note that if you compile (or start the interpreter) with the -Wincomplete-patterns flag (warnings for incomplete patterns), Haskell will automatically warn you that your function definitions are not complete, and that there are input patterns for which you have not defined a clause.
To answer your "main" question,
*Main> let (x:xs) = [] -- (1)
means, when x's or xs's value is required, match (x:xs) with [] and use the resulting bindings. The match will never succeed, and any such attempt will always result in patter-matching failure error.
So why wasn't it?
*Main> (x:xs) == [] -- (2)
Now this means, try to compare (x:xs) and []. Both are lists; comparing lists involves pattern matching the top structure and then proceeding recursively comparing the components, on success -- returning False on failure (not actually failing). Thus a match between (_:_) and [] is tried, and fails, resulting in an immediate return of the False value as the result of the comparison.
Note that values bound to x and xs were not requested at any point; hence there was no error because the matching of (x:xs) and [] in (1) was never triggered.
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.
What would be the syntax (if possible at all) for returning the list of lists ([[a]]) but without the use of empty list ([]:[a])?
(similar as the second commented guard (2) below, which is incorrect)
This is a function that works correctly:
-- Split string on every (shouldSplit == true)
splitWith :: (Char -> Bool) -> [Char] -> [[Char]]
splitWith shouldSplit list = filter (not.null) -- would like to get rid of filter
(imp' shouldSplit list)
where
imp' _ [] = [[]]
imp' shouldSplit (x:xs)
| shouldSplit x = []:imp' shouldSplit xs -- (1) this line is adding empty lists
-- | shouldSplit x = [imp' shouldSplit xs] -- (2) if this would be correct, no filter needed
| otherwise = let (z:zs) = imp' shouldSplit xs in (x:z):zs
This is the correct result
Prelude> splitWith (== 'a') "miraaaakojajeja234"
["mir","koj","jej","234"]
However, it must use "filter" to clean up its result, so I would like to get rid of function "filter".
This is the result without the use of filter:
["mir","","","","koj","jej","234"]
If "| shouldSplit x = imp' shouldSplit xs" is used instead the first guard, the result is incorrect:
["mirkojjej234"]
The first guard (1) adds empty list so (I assume) compiler can treat the result as a list of lists ([[a]]).
(I'm not interested in another/different solutions of the function, just the syntax clarification.)
.
.
.
ANSWER:
Answer from Dave4420 led me to the answer, but it was a comment, not an answer so I can't accept it as answer. The solution of the problem was that I'm asking the wrong question. It is not the problem of syntax, but of my algorithm.
There are several answers with another/different solutions that solve the empty list problem, but they are not the answer to my question. However, they expanded my view of ways on how things can be done with basic Haskell syntax, and I thank them for it.
Edit:
splitWith :: (Char -> Bool) -> String -> [String]
splitWith p = go False
where
go _ [] = [[]]
go lastEmpty (x:xs)
| p x = if lastEmpty then go True xs else []:go True xs
| otherwise = let (z:zs) = go False xs in (x:z):zs
This one utilizes pattern matching to complete the task of not producing empty interleaving lists in a single traversal:
splitWith :: Eq a => (a -> Bool) -> [a] -> [[a]]
splitWith f list = case splitWith' f list of
[]:result -> result
result -> result
where
splitWith' _ [] = []
splitWith' f (a:[]) = if f a then [] else [[a]]
splitWith' f (a:b:tail) =
let next = splitWith' f (b : tail)
in if f a
then if a == b
then next
else [] : next
else case next of
[] -> [[a]]
nextHead:nextTail -> (a : nextHead) : nextTail
Running it:
main = do
print $ splitWith (== 'a') "miraaaakojajeja234"
print $ splitWith (== 'a') "mirrraaaakkkojjjajeja234"
print $ splitWith (== 'a') "aaabbbaaa"
Produces:
["mir","koj","jej","234"]
["mirrr","kkkojjj","jej","234"]
["bbb"]
The problem is quite naturally expressed as a fold over the list you're splitting. You need to keep track of two pieces of state - the result list, and the current word that is being built up to append to the result list.
I'd probably write a naive version something like this:
splitWith p xs = word:result
where
(result, word) = foldr func ([], []) xs
func x (result, word) = if p x
then (word:result,[])
else (result, x:word)
Note that this also leaves in the empty lists, because it appends the current word to the result whenever it detects a new element that satisfies the predicate p.
To fix that, just replace the list cons operator (:) with a new operator
(~:) :: [a] -> [[a]] -> [[a]]
that only conses one list to another if the original list is non-empty. The rest of the algorithm is unchanged.
splitWith p xs = word ~: result
where
(result, word) = foldr func ([], []) xs
func x (result, word) = if p x
then (word ~: result, [])
else (result, x:word)
x ~: xs = if null x then xs else x:xs
which does what you want.
I guess I had a similar idea to Chris, I think, even if not as elegant:
splitWith shouldSplit list = imp' list [] []
where
imp' [] accum result = result ++ if null accum then [] else [accum]
imp' (x:xs) accum result
| shouldSplit x =
imp' xs [] (result ++ if null accum
then []
else [accum])
| otherwise = imp' xs (accum ++ [x]) result
This is basically just an alternating application of dropWhile and break, isn't it:
splitWith p xs = g xs
where
g xs = let (a,b) = break p (dropWhile p xs)
in if null a then [] else a : g b
You say you aren't interested in other solutions than yours, but other readers might be. It sure is short and seems clear. As you learn, using basic Prelude functions becomes second nature. :)
As to your code, a little bit reworked in non-essential ways (using short suggestive function names, like p for "predicate" and g for a main worker function), it is
splitWith :: (Char -> Bool) -> [Char] -> [[Char]]
splitWith p list = filter (not.null) (g list)
where
g [] = [[]]
g (x:xs)
| p x = [] : g xs
| otherwise = let (z:zs) = g xs
in (x:z):zs
Also, there's no need to pass the predicate as an argument to the worker (as was also mentioned in the comments). Now it is arguably a bit more readable.
Next, with a minimal change it becomes
splitWith :: (Char -> Bool) -> [Char] -> [[Char]]
splitWith p list = case g list of ([]:r)-> r; x->x
where
g [] = [[]]
g (x:xs)
| p x = case z of []-> r; -- start a new word IF not already
_ -> []:r
| otherwise = (x:z):zs
where -- now z,zs are accessible
r#(z:zs) = g xs -- in both cases
which works as you wanted. The top-level case is removing at most one empty word here, which serves as a separator marker at some point during the inner function's work. Your filter (not.null) is essentially fused into the worker function g here, with the conditional opening1 of a new word (i.e. addition1 of an empty list).
Replacing your let with where allowed for the variables (z etc.) to became accessible in both branches of the second clause of the g definition.
In the end, your algorithm was close enough, and the code could be fixed after all.
1 when thinking "right-to-left". In reality the list is constructed left-to-right, in guarded recursion ⁄ tail recursion modulo cons fashion.