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.
Related
I need some help in Haskell. I'm new to haskell. I want to find middle element of the list but I want to do this in a function. I tried to find length of list and division to 2. But I failed to get length of list as int in a function.
findListL k = [z | let z = length k]
I tried the code at the top but I failed.
Can Someone tell me how to do it?
We can approach this problem with a tortoise and hare approach. We concurrently iterate with two iterators over the same list. The hare each time takes two steps, whereas the tortoise moves one step forward. If the hare reaches the end, then the tortoise is in the middle. We can thus implement this as:
findListL :: [a] -> a
findListL zs = go zs zs
where go (_:_:xs) ~(_:ys) = go xs ys
go _ (y:_) = y
This then produces:
Prelude> findListL []
*** Exception: <interactive>:(3,9)-(4,22): Non-exhaustive patterns in function go
Prelude> findListL [1]
1
Prelude> findListL [1,2]
2
Prelude> findListL [1,2,3]
2
Prelude> findListL [1,2,3,4]
3
For an empty list, this will raise an error, for a list with an even length, it will take the element at index (n+1)/2.
Since the computation for an empty list does not work, one often constructs a function that returns a Maybe a, and thus a Just y in case we found an element y in the middle, and a Nothing in case the list is empty. I leave that as an exercise.
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!
I'm tasked with implementing a function that returns the Thue-Morse sequence all the way through. I've done it through primitive recursion but now I have to do it with a circular list (using list comprehension), and it'd have to return this when I call take on it:
>take 4 thueSeq
[[0],[0,1],[0,1,1,0],[0,1,1,0,1,0,0,1]]
Here's my (horrible) attempt at implementation:
> thueSeq = 0: [x | x <- zipWith (mod) (tail thueSeq) [1] ]
I'm aware right off the bat that it's wrong (the head is supposed to be [0], not 0) but writing [0] ++ [0,1] ++ ... didn't return a list of lists anyway.
My question is, first off, how do I "start off" the list with [[0],[0,1]] because from what I've seen with circular lists, they have the base cases and then recurse through. Secondly, my list comprehension is trying to apply (mod x 1) to each value, but that'd also be wrong since [[0,1]] would turn into [[0,1,0]] instead of [[0,1,1,0]]. So I'm thinking I have to apply it on every other element in the list (the 1st element, 3rd, 5th, etc.)?
From what I understand...
I have just written a simple flip function that maps 1 to 0 and 0 to 1
flipBit 1 = 0
flipBit 0 = 1
the function h takes a list and joins that list with the flipped version of the list
h xs = xs ++ (map flipBit xs)
*Main> h [0]
[0,1]
The main function fseq takes a list as an argument. It conses the argument into the recursive call
fseq xs = xs : fseq (h xs)
*Main> take 4 $ fseq [0]
[[0],[0,1],[0,1,1,0],[0,1,1,0,1,0,0,1]]
Haskell provides the function iterate :: (a -> a) -> a -> [a] that does exactly this.
We can now wrap this as follows:
thue_morse = fseq [0]
or using the function iterate
thue_morse = iterate h [0]
both give the result
*Main> take 4 thue_morse
[[0],[0,1],[0,1,1,0],[0,1,1,0,1,0,0,1]]
If you wanted to use list comprehensions, you could write something like this:
h xs = xs ++ (map flipBit xs)
thue_morse = [0] : [ h x | x <- thue_morse]
I need to generate infinite sorted list of all coprimes.
The first element in each pair must be less than the second.
The sorting must be done in ascending order -- by the sum of pair's elements; and if two sums are equal, then by the pair's first element.
So, the resulting list must be
[(2,3),(2,5),(3,4),(3,5),(2,7),(4,5),(3,7),(2,9),(3,8),(4,7)...`
Here's my solution.
coprimes :: [(Int, Int)]
coprimes = sortBy (\t1 t2 -> if uncurry (+) t1 <= uncurry (+) t2 then LT else GT) $ helper [2..]
where helper xs = [(x,y) | x <- xs, y <- xs, x < y, gcd x y == 1]
The problem is that I can't take n first pairs. I realize that sorting can't be done on infinite lists.
But how can I generate the same sequence in a lazy way?
While probably not the most optimal way it should works if you first generate all possible pairs and then filter them.
So using your criteria:
pairs :: [(Integer,Integer)]
pairs = [ (i,l-i) | l <- [1..], i <- [1..l-1] ]
coprimes :: [(Integer,Integer)]
coprimes = [ (i,j) | (i,j) <- pairs, 1 < i, i < j,gcd i j == 1]
produces
λ> take 10 coprimes
[(2,3),(2,5),(3,4),(3,5),(2,7),(4,5),(3,7),(2,9),(3,8),(4,7)]
now of course you can put some of the stuff 1 < i and i < j comes to mind into the pairs definition or even join them but I think here it's more obvious what's going on
Here's a possible solution following Chapter 9 of Richard Bird's Thinking Functionally in Haskell:
coprimes = mergeAll $ map coprimes' [2..]
coprimes' n = [(n, m) | m <- [n+1..], gcd m n == 1]
merge (x:xs) (y:ys)
| s x < s y = x:merge xs (y:ys)
| s x == s y = x:y:merge xs ys
| otherwise = y:merge (x:xs) ys
where s (x, y) = x+y
xmerge (x:xs) ys = x:merge xs ys
mergeAll = foldr1 xmerge
And the result is:
> take 10 $ coprimes
[(2,3),(2,5),(3,4),(3,5),(2,7),(4,5),(3,7),(2,9),(3,8),(4,7)]
Note that the natural definition of mergeAll would be foldr1 merge, but this doesn't work because it will try to find the minimum of the first elements of all the list before returning the first element, and hence you end up in an infinite loop. However, since we know that the lists are in ascending order and the minimum is the first element of the first list xmerge does the trick.
Note: this solution appears to be significantly (like 2 order of magnitudes) slower than Carsten "naive" answer. So I advise to avoid this if you are interested in performance. Yet it still is an interesting approach that might be effective in other situations.
As #Bakuriu suggests, merging an infinite list of infinite lists is a solution, but the devil is in the details.
The diagonal function from the universe-base package can do this, so you could write:
import Data.Universe.Helpers
coprimes = diagonal [ go n | n <- [2..] ]
where go n = [ (n,k) | k <- [n+1..], gcd n k == 1 ]
Note - this doesn't satisfy your sorted criteria, but I mention it because the functions in that package are useful to know about, and implementing a function like diagonal correctly is not easy.
If you want to write your own, consider decomposing the infinite grid N x N (where N is the natural numbers) into diagonals:
[ (1,1) ] ++ [ (1,2), (2,1) ] ++ [ (1,3), (2,2), (3,1) ] ++ ...
and filtering this list.
I need to generate infinite sorted list of all coprimes. The first element in each pair must be less than the second. The sorting must be done in ascending order -- by the sum of pair's elements; and if two sums are equal, then by the pair's first element.
So, we generate ascending pairs of sum and first element, and keep only the coprimes. Easy cheesy!
[ (first, second)
| sum <- [3..]
, first <- [2..sum `div` 2]
, let second = sum-first
, gcd first second == 1
]
I have a list of doubles(myList), which I want to add to a new List (someList), but once the new list reaches a set size i.e. 25, I want to stop adding to it. I have tried implementing this function using sum but was unsuccessful. Example code below.
someList = [(a)| a <- myList, sum someList < 30]
The way #DanielFischer phrased the question is compatible with the Haskell way of thinking.
Do you want someList to be the longest prefix of myList that has a sum < 30?
Here's how I'd approach it: let's say our list is
>>> let list = [1..20]
we can find the "cumulative sums" using:
>>> let sums = tail . scanl (+) 0
>>> sums list
[1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136,153,171,190,210]
Now zip that with the original list to get pairs of elements with the sum up to that point
>>> zip list (sums list)
[(1,1),(2,3),(3,6),(4,10),(5,15),(6,21),(7,28),(8,36),
(9,45),(10,55),(11,66),(12,78),(13,91),(14,105),(15,120),
(16,136),(17,153),(18,171),(19,190),(20,210)]
Then we can takeWhile this list to get the prefix we want:
>>> takeWhile (\x -> snd x < 30) (zip list (sums list))
[(1,1),(2,3),(3,6),(4,10),(5,15),(6,21),(7,28)]
finally we can get rid of the cumulative sums that we used to perform this calculation:
>>> map fst (takeWhile (\x -> snd x < 30) (zip list (sums list)))
[1,2,3,4,5,6,7]
Note that because of laziness, this is as efficient as the recursive solutions -- only the sums up to the point where they fail the test need to be calculated. This can be seen because the solution works on infinite lists (because if we needed to calculate all the sums, we would never finish).
I'd probably abstract this and take the limit as a parameter:
>>> :{
... let initial lim list =
... map fst (takeWhile (\x -> snd x < lim) (zip list (sums list)))
... :}
This function has an obvious property it should satisfy, namely that the sum of a list should always be less than the limit (as long as the limit is greater than 0). So we can use QuickCheck to make sure we did it right:
>>> import Test.QuickCheck
>>> quickCheck (\lim list -> lim > 0 ==> sum (initial lim list) < lim)
+++ OK, passed 100 tests.
someList = makeList myList [] 0 where
makeList (x:xs) ys total = let newTot = total + x
in if newTot >= 25
then ys
else makeList xs (ys ++ [x]) newTot
This takes elements from myList as long as their sum is less than 25.
The logic takes place in makeList. It takes the first element of the input list and adds it to the running total, to see if it's greater than 25. If it is, we shouldn't add it to the output list, and we finish recursing. Otherwise, we put x on the end of the output list (ys) and keep going with the rest of the input list.
The behaviour you want is
ghci> appendWhileUnder 25 [1..5] [1..5]
[1,2,3,4,5,1,2,3]
because that sums to 21 and adding the 4 would bring it to 25.
OK, one way to go about this is by just appending them with ++ then taking the initial segment that's under 25.
appendWhileUnder n xs ys = takeWhileUnder n (xs++ys)
I don't want to keep summing intermediate lists, so I'll keep track with how much I'm allowed (n).
takeWhileUnder n [] = []
takeWhileUnder n (x:xs) | x < n = x:takeWhileUnder (n-x) xs
| otherwise = []
Here I allow x through if it doesn't take me beyond what's left of my allowance.
Possibly undesired side effect: it'll chop out bits of the original list if it sums to over 25. Workaround: use
appendWhileUnder' n xs ys = xs ++ takeWhileUnder (n - sum xs)
which keeps the entire xs whether it brings you over n or not.