Having Trouble Understanding Haskell Merging Function - list

I have an assignment to make a Haskell function to merge 2 lists together without using the ++ operation. I found the following code online and it works as intended but I need help understanding how and why it works. If someone can take me through a step by step on how this function works, I would greatly appreciate it. I am VERY new to Haskell so assume you are explaining this to a 5 year old lol.
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : (merge xs ys)

A list in Haskell is defined as a linked list, with [] as the empty list, and (:) is the "cons" where the first parameter is the head (the first element), and the second element the tail (so a list with the remaining elements). This thus means that a list like [1,4] is represented as (1 : (4 : [])), or more can canonical (:) 1 ((:) 4 []).
If we now want to merge two lists [1,4] and [2,5] for example we thus call merge with merge (1 : (4 : [])) (2 : (5 : [])). The first rule of merge checks if the first parameter is an empty list, which is not the case, so we continue the second rule. This checks if the first list uses a cons data constructor, which is the case. So it unifies x with the head of the list (here 1), and xs with the rest of the list (here [4]). This thus means that it replaces this with:
merge (1 : (4 : [])) (2 : (5 : [])) -> 1 : merge (4 : []) (2 : (5 : []))
Now in the recursive call, the first clause will be checked again, but (:) 4 [] again does not match with the empty list [], so we check the second clause, and again this matches. So in this call x unifies with 4, and xs with []:
merge (4 : [])) (2 : (5 : [])) -> 4 : merge [] (2 : (5 : []))
the last recursion has the empty list data constructor as first parameter. This thus matches with the pattern in the first clause. We thus return the second list:
merge [] (2 : (5 : [])) -> (2 : (5 : []))
the result is thus a list:
(1 : (4 : (2 : (5 : []))))
or in short:
[1,4,2,5]

A list is either empty, or non-empty. If it's non-empty, then it has a head (the first element) and a tail (the rest of the list, minus that first element). If we can say what merge does when its first argument meets both of those cases, then we will have handled every possible case - because that first list, being a list, is either empty or not.
So suppose first we are merging the empty list with another list. In this case, clearly the result is just that other list - there's nothing to merge. This is the easy case, covered in the first line of the function: merge [] ys = ys.
So we're left with the case where the first list is non empty. As previously stated, that means it has a head and a tail. It should be easy to see that, in merging this list with another, the result is the same as if we were to merge the tail with the other list, then add the head to the front afterwards. That's what the second line of the function says, in the language of pattern matching (in particular using the "cons" constructor (:) for breaking a list into a head and tail): merge (x:xs) ys = x : (merge xs ys).
Once we have those, we can compute merge for any two lists. Not only do these two cases cover all possible ones, but crucially they allow us to "work backwards" to always get an answer - because in the recursive case, we express merge (x:xs) in terms of merge xs, and xs is shorter than (x:xs), so by repeating this process we always eventually get back to the empty list case*
A simple example should demonstrate: merge [1, 2, 3] [4, 5, 6] successively becomes:
1 : (merge [2, 3] [4, 5, 6])
1 : (2 : (merge [3] [4, 5, 6]))
1 : (2 : (3 : (merge [] [4, 5, 6])))
1 : (2 : (3 : [4, 5, 6]))
whic we would more normally write as [1, 2, 3, 4, 5, 6].
*actually, this argument relies on that first list being finite. If it's infinite, the recursion never stops - but this still isn't a problem, as the process still allows us to compute any finite number of elements as we want. In fact the result is simply that first list, for any finite number of elements. But don't worry about this case too much if it doesn't make sense to you yet, infinite data structures don't turn up every day!

Related

How does recursion work in Haskell? - Example merge function

if we look at the funtion definition of merge
merge (x:xs) (y:ys) | x <= y = x:merge xs (y:ys)
| otherwise = y:merge (x:xs) ys
With the input [2,3] [4,1]
the first step looks like this
2<=4 => 2:merge [3] (1:[4])
Here my question lies: The first head element of the second list was 4 but since 2<=4 nothing was done with 4 so the 4 has to be still in the second list but the 4 needs to be the last element in the list now so 3 can be compared to the 1. I wonder how the compiler changes the second list: At first 4 was the head element but since it makes none sense to compare the 3 to the 4 again the indices has to be switched.
So the compiler just put the head element to the end of the list after the first comparison? Or what does the compiler do here?
I wonder how the compiler changes the second list.
It does not. If we call merge [2,3] [4,1] then the clause you describe will fire, with: x = 2, y = 4, xs = [3] and ys = [1]. It will indeed check that 2 <= 4, which holds, and then call merge with:
x : merge xs (y:ys)
so that means that if we use the variables we just assigned, we get:
2 : merge [3] (4:[1])
or less verbose:
2 : merge [3] [4,1]
I wonder how the compiler changes the second list: At first 4 was the head element but since it makes none sense to compare the 3 to the 4 again the indices has to be switched.
Such merge function often has a precondition that the two lists it aims to merge, are sorted individually already. So normally merge [2,3] [4,1] will not be called with an algorithm like MergeSort, the two lists are first sorted, and then it is thus called with merge [2,3] [1,4].
3 isn't compared to 1 until it has been compared to 4 as well; merge preserves the relative order of each value within a single list.
The recursion proceeds as follows:
merge [2,3] [4,1] == 2 : merge [3] [4,1] -- 2 < 4
== 2 : 3 : merge [] [4, 1] -- 3 < 4
== 2 : 3 : [4, 1] -- assuming merge [] ys == ys
Don't confuse merge with mergeSort, which uses merge as a subroutine.
mergeSort [] = []
mergeSort xs = merge (mergeSort first) (mergeSort second)
where (first, second) = split xs
split xs = ... -- some function to split a list roughly in half
The order-preserving behavior of merge is what makes mergeSort a stable sorting algorithm.

How to move 1 element of a List to right or left in Haskell?

Hi I have been looking for an answer but could not find one. Lets say that we have a list like [1,10,4,5,3] how can I shift 5 to left so that this list becomes [1,10,5,4,3].
I tried to swapElementsAt by finding the index of that element but it looks very insufficient.
swapElementsAt :: Int -> [a] -> [a]
swapElementsAt n list = let (beg, a:b:rest) = splitAt (n-1) list in beg ++ b:a:rest
It works like
λ> swapElementsAt 3 [1,10,4,5,3]
[1,10,5,4,3]
Consider how would you write this function if you were to traverse the input list from left to right looking at a very local vicinity of the beginning of the list (since that's what you can easily pattern-match on).
The most straightforward way would be to pattern-match on the first two elements, and check if the second element matches your pattern. If so, just build a new list by swapping these elements and appending the remainder of the list, otherwise, go recursively over the rest.
In code:
swapElem :: Eq a => a -> [a] -> [a]
swapElem e (x:y:xs) | y == e = y : x : xs
swapElem e (x:xs) = x : swapElem e xs
swapElem _ [] = []
The first pattern only matches when there are at least two elements in the list, and the second element is equal to the desired one. If there are less elements or the second element is not the right one, it will fall through to the second pattern, that matches arbitrary non-empty list and calls swapElem on the remainder of the list. The third pattern is there to provide the base recursion case of an empty input list.
Note this code only changes the first occurrence of the target element:
Prelude> swapElem 5 [1, 10, 4, 5, 3]
[1,10,5,4,3]
Prelude> swapElem 5 [1, 10, 5, 4, 5, 3]
[1,5,10,4,5,3]
How would you change it so that it left-shifts all 5s?
Also, the answer depends on what exactly is your input. The answer by #Scarabyte considers the case where you're given the position of the target element, while this approach instead considers the element that you want to shift left.

Haskell recurse and add to a list

I'm a Haskell beginner,
I have a function
func :: Num a => [a] -> [a]
func [] = []
func (x:xs) = x + func xs
Each recursion I want to append the value to a list for my output. This function will sum consecutive indexes in a list so that the input [1, 2, 3, 4] produces [1, 3, 6, 10].
How do I append the value generated each time to my list?
Your problem here isn't how to append, but rather how to calculate the value in the first place. Each item needs to be substituted with a sum of itself with all the items preceding it.
Here is one way to do it:
Prelude> func (x:xs) = x:map (+ x) (func xs); func [] = []
Prelude> func [1, 2, 3, 4]
[1,3,6,10]
How does this work? We're given a list that starts with the element x and has the remaining elements xs. We want to increment every item in xs by x, after recursively applying the algorithm to xs.
This is what x:map (+ x) (func xs) does. It reads as "prepend x to the result of mapping every element in func xs through an increment by x".
E.g. for [1, 2, 3, 4], we want 1 to be added to every member of the result of recursively applying the algorithm to [2, 3, 4], then prepended. For [2, 3, 4] we want 2 to be ... to [3, 4]. And so on, until eventually for [4] we want 4 to be added and prepended to the result of applying the algorithm to [].
This is where our base case (func [] = []) kicks in: the algorithm is defined so that it returns an empty list unchanged. Hence func [4] is [4], func [3, 4] is [3, 7], and you keep incrementing and prepending until you get [1,3,6,10].
I think in this particular case, you could use scanl1 like:
scanl1 (+) [1,2,3,4] -- [1,3,6,10]
When iterating over lists, we often use folds, which is a way of reducing the list to a particular value.
There's also another type of operation, which is a fold that collects all results along the way, and that's called a scan (from the docs):
scanl = scanlGo
where
scanlGo :: (b -> a -> b) -> b -> [a] -> [b]
scanlGo f q ls = q : (case ls of
[] -> []
x:xs -> scanlGo f (f q x) xs)
So the scan takes three arguments: a function that takes two values and returns a value, a starter value, and a list of values.
The scan will then return a list.
Thus, what you need is a function that takes two values and returns something of the same type as the first (it's okay if both are the same). Binary addition would work here: +.
You also need a value to start off with (the b, which is the second argument to our function), and 0 is the identity for integer addition, so we should use that.
Finally, we pass your list to get the result.
Try to figure out how to write you function as a fold and then as a scan and you will discover the answer.

Manipulating Lists in Haskell using Higher-Order Functions and Lambda Calculus

I am trying to write a very simple function that takes a list (for example : [1,2,3,1,5]) and returns a list of elements that are directly after a specific element.
What I have reached so far is:
function element list = filter (\x -> element:x) list
My desired output:
function 1 [1,2,3,1,5]
=>   [2,5]
Try this
map snd $ filter ((== x) . fst) $ zip theList (tail theList)
This won't work on an empty list, you will still need extra code to deal with that.
How does this work?
First, note that the values flow from right to left. The ($) operator allows this to happen. So, the first part evaluated is the zip function.
zip theList (tail theList)
For your example above, this would yield
zip [1,2,3,1,5] [2,3,1,5]
equaling
[(1,2), (2, 3), (3, 1), (1,5)]
which is the set of concurrent pairs in the list.
Next, the filter is applied
filter ((== x) . fst) $ ....
In English, what this says is, filter out only the concurrent pairs whose first element equals x. The output is
[(1,2), (1,5)]
Now we have the list of concurrent pairs starting with 1.
Finally, we apply the map
map snd $ ....
This just pulls out the second value of the pair.
map snd [(1,2), (1,5)] = [2,5]
which is the desired value.
Note, my comment above about failing on the empty list.
This is because tail crashes on the empty list
tail [] --error
There are ways to patch this behavior (see the safe package, for instance), but it is mostly bookkeeping at this point, so I left that for you to work out.
Also note that since all of the functions we used are lazy, this approach would work for lists of infinite length as well.
You can do this quite easily with a simple list comprehension, e.g.:
successors xs i = [y | (x,y) <- zip xs (drop 1 xs), x == i]
This will work to your specifications
next x (i:y:ys) -- look at the first two items in the list
| x == i = -- if the first item == x,
y : next x (y:ys) -- take the second, and continue minus the first element
|otherwise = -- not equal,
next x (y:ys) -- so skip that element
next _ [_] = [] -- if there's no second element, then stop
next _ _ = [] -- if the list is empty, stop

Swap first and last element haskell

Im trying to swap the first and last element of a list in haskell. I've tried pattern matchnig, expressions, functions, etc. This is my last attempt:
cambio xs = [ cabeza++([x]++cola)|x<-xs, cabeza <- init x, cola <- last x, drop 1 x, drop 0 ([init x])]
My compiler throws the next error:
Couldn't match expected type `Bool' with actual type `[a0]'
In the return type of a call of `drop'
In the expression: drop 1 x
In a stmt of a list comprehension: drop 1 x
Can anyone help me? I've tried to do this for 2 days
Here are a few hints:
You can't solve this with list comprehension.
Identify the base (trivial) cases - empty list and list of one element. Write equations that cover those cases.
In all other cases the length of the input list will be >= 2. The list you want is
[z] ++ xs ++ [a]
where z is the last element, a the first element of the input list and xs the middle part of the input.
Now tell me (or yourself), how long will xs be, if the length of the input string was k?
Write the equation that covers the case of lists with more than 1 elements. You can use functions like head, last, length, drop or take.
I think that lists aren't the best data structure for doing this, but here it goes:
swap list = last list : (init . tail $ list) ++ [head list]
This is going to require traversing the list and will be slow on long lists. This is the nature of linked lists.
Updated with base cases from question asker:
swap [] = []
swap [a] = [a]
swap list = last list : (init . tail $ list) ++ [head list]
This is a fairly straightforward thing to do, especially with the standard list functions:
swapfl [] = []
swapfl [x] = [x]
swapfl (x:xs) = (last xs : init xs) ++ [x]
Or without them (although this is less readable and usually not done, and not recommended):
swapfl' [] = []
swapfl' [x] = [x]
swapfl' (x:xs) = let (f, g) = sw x xs in f:g
where sw k [y] = (y, [k])
sw k (y:ys) = let (n, m) = sw k ys in (n, y:m)
Or one of many other ways.
I hope that helps ... I know I didn't do much explaining, but frankly, it's hard to tell exactly what you were having trouble with as far as this function is concerned, seeing as you also seem to completely misunderstand list comprehensions. I think it might be most beneficial if I explain those instead?
And why this cant be solved with a list comprehension? I tough they were like functions but with a different form
Not really. List comprehensions are useful for easily defining lists, and they're very closely related to set-builder notation in mathematics. That would not be useful for this particular application, because, while they're very good at modifying the elements of a list, comprehensions are not very good at reordering lists.
In a comprehension, you have three parts: the definition of an element in the list, one or more input lists, and zero or more predicates:
[ definition | x <- input1, y <- input2, predicate1, predicate2 ]
The definition describes a single element of the list we're making, in terms of the variables the arrows in the inputs are pointing at (x and y in this case). Each input has a list on the right of the arrow, and a variable on the left. Each element in the list we're making is built by extracting each combination of elements from the input lists into those variables, and evaluating the definition part using those values. For example:
[ x + y | x <- [1, 3], y <- [2, 4] ]
This generates:
[1 + 2, 1 + 4, 3 + 2, 3 + 4] == [3, 5, 5, 7]
Also, you can include predicates, which are like filters. Each predicate is a boolean expression defined in terms of the input elements, and each is evaluated whenever a new list element is. If any of the predicates come out to be false, those elements aren't put in the list we're making.
Let's look at your code:
cambio xs = [ cabeza++([x]++cola) | x<-xs, cabeza <- init x, cola <- last x,
drop 1 x, drop 0 ([init x])]
The inputs for this comprehension are x <- xs, cabeza <- init x, and cola <- last x. The first one means that every element in xs is going to be used to define elements for the new list, and each element is going to be named x. The other two don't make any sense, because init and last are type [a] -> a, but are on the right side of the arrow and so must be lists, and x must be an element of a list because it's on the left side of its arrow, so in order for this to even compile, xs would have to be type [[[a]]], which I'm sure is not what you want.
The predicates you used are drop 1 x and drop 0 [init x]. I kind of understand what you were trying to do with the first one, dropping the first element of the list, but that wouldn't work because x is just an element of the list, not the list itself. In the second one, drop 0 means "remove zero elements from the beginning of the following list", which would do absolutely nothing. In either case, putting something like that in a predicate wouldn't work because the predicate needs to be a boolean value, which is why you got the compiler error. Here's an example:
pos xs = [ x | x <- xs, x >= 0 ]
This function takes a list of numbers, removes all the negative numbers, and returns the result. The predicate is the x >= 0, which is a boolean expression. If the expression evaluates to false, the element being evaluated is filtered out of the resulting list.
The element definition you used is cabeza ++ [x] ++ cola. This means "Each element in the resulting list is itself a list, made up of all elements in the list cabeza, followed by a single element that contains x, followed by all elements in the list cola", which seems like the opposite of what you were going for. Remember that the part before the pipe character defines a single element, not the list itself. Also, note that putting square brackets around a variable creates a new list that contains that variable, and only that variable. If you say y = [x], this means that y contains a single element x, and doesn't say anything about whether x is a list or not.
I hope that helps clear some things up.