Merge sort in haskell goes in infinite loop - haskell

Hi everybody I am attempting to reproduce merge sort in haskel, here is my code:
-- merge
merge :: (Ord a) => [a] -> [a] -> [a]
merge [] [] = []
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys)
| x <= y = x:(merge xs (y:ys))
| otherwise = y:(merge (x:xs) ys)
-- split
splitIn2 :: (Ord a) => [a] -> ([a],[a])
splitIn2 [] = ([],[])
splitIn2 xs = splitAt ((length xs `div` 2)+1) xs
-- msort
msort :: (Ord a) => [a] -> [a]
msort [] = []
msort [x] = [x]
msort (xs) = merge (msort as) (msort bs)
where (as,bs) = splitIn2 xs
It compiles on ghc, and it works for:
*Main> msort([])
[]
*Main> msort([1])
[1]
However it doesnt do its job properly because it starts too loop infinitely (at least this is what I thought) and it doesnt print anything.
I think it is because I dont remove elements from the lists like I did in other recursive experiment, any suggestion?

The problem is that when length xs == 2,
(length xs `div` 2) + 1
= (2 `div` 2) + 1
= 1 + 1
= 2
and splitAt 2 xs returns (xs, []). Since the first list is still of length 2,
msort will try to splitIn2 it down again in an infinite loop.
To solve this, you can simply get rid of the +1; it's completely unnecessary. You can
also eliminate the special case for the empty list, since splitAt 0 [] = ([], []).
splitIn2 xs = splitAt (length xs `div` 2) xs

*Main> splitIn2 [1, 2, 3, 0, 5, 6]
([1,2,3,0],[5,6])
And after small change (deleting +1 ):
splitIn2 xs = splitAt ((length xs `div` 2)) xs
It works:
*Main> splitIn2 [1, 2, 3, 0, 5, 6]
([1,2,3],[0,5,6])
*Main> msort [1, 2, 3, 0, 5, 6]
[0,1,2,3,5,6]

Related

Return a list, which contains a pair of elements, but only if the respective elements' sums are odd

Implement the oddPairs :: [Int] -> [Int] -> [(Int, Int)] function that returns a list of pairs, but only if the parameters' lists' respective elements' sums are odd.
For example:
oddPairs [1,2,3] [2,2,2] == [(1,2),(3,2)]
oddPairs [1,3,5] [2,4,6] == zip [1,3,5] [2,4,6]
oddPairs [1,2,3] [1,2,3] == []
So far, I've tried
oddPairs (x:xs) (y:ys) | (x+y) `mod` 2 == 0 = []
| (x+y) `mod` 2 /= 0 = [(x, y)] ++ oddPairs (xs) (ys)
And on the first example, it returns only [(1,2)], on the second, it returns the correct values but with a Non-exhaustive patterns error.
In case the two items are even, you should not just return an empty list, but continue the recursion until at least one of the lists is exhausted, so:
oddPairs :: Integral a => [a] -> [a] -> [(a, a)]
oddPairs [] _ = []
oddPairs _ [] = []
oddPairs (x:xs) (y:ys)
-- keep searching for new items &downarrow;
| (x+y) `mod` 2 == 0 = oddPairs xs ys
| otherwise = (x, y) : oddPairs xs ys
Another way to look at the problem is that you want only the pairs that have an odd sum. This is a slight difference in emphasis that might lead to the following.
Use the zip function to combine each list into pairs. Then use filter to find the ones with odd sum.
oddPairs :: Integral a => [a] -> [a] -> [(a, a)]
oddPairs f s = filter oddPair (zip f s)
where oddPair (l, r) = not $ even (l + r)
Quite straightforwardly with a list comprehension:
oddPairs :: [Int] -> [Int] -> [(Int, Int)]
oddPairs ms ns = [(m, n) | (m, n) <- zip ms ns, odd (m + n)]
Indeed:
> oddPairs [1, 2, 3] [2, 2, 2] == [(1, 2),(3, 2)]
True
> oddPairs [1, 3, 5] [2, 4, 6] == zip [1, 3, 5] [2, 4, 6]
True
> oddPairs [1, 2, 3] [1, 2, 3] == []
True

haskell mergesort implementation compiles but does not return anything

Here is my implementation:
mergesort :: (Ord a) => [a] -> [a]
mergesort list = merge (mergesort (left list)) (mergesort (right list))
where
left xs = take (div (length xs) 2) xs
right xs = drop (div (length xs) 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
The code compiles but when I run it my machine crashes. What am I doing wrong?
You are missing base cases - so you get infinite recursion. Trying stepping through your example with lists like [] or [1] and you'll fall straight into the problem.
mergesort :: (Ord a) => [a] -> [a]
mergesort [] = [] -- < ADDED
mergesort [x] = [x] -- < ADDED
mergesort list = merge (mergesort (left list)) (mergesort (right list))
where
left xs = take (div (length xs) 2) xs
right xs = drop (div (length xs) 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys

calculating number of inversions in a list in haskell

how do we get calculate inversions in a list in Haskell?
eg. [1, 2, 3, 1] , xi > xj where i < j is the condition for inversion. In the given example it would be 3.
I tried the following code:
module Inversion where
inv :: Ord a => [a] -> [(a, a)]
inv [] = []
inv xs = [(a, b) | a <- xs, b <- tail xs, a > b]
I even tried to zip it with tail and then get the pairs.
import Data.List
inv :: Ord a => [a] -> [(a, a)]
inv xs = [(a,b) | (a:bs) <- tails xs, b <- bs, a > b]
This is a naive implementation close to what you already got:
inv :: Ord a => [a] -> [(a, a)]
inv [] = []
inv xs = [(a, b) | b <- xs', a > b] ++ inv xs'
where xs' = tail xs
a = head xs
It does the first thing that comes to mind: compare the first element with every other element in the list and then do the same with the rest of the list.
Your example:
*Main> inv [1,2,3,1]
[(2,1),(3,1)]
This seems to work for me:
inv lst = filter nonOrdPair $ zip lst (tail lst)
where nonOrdPair (a,b) = a > b
on your example gives
Prelude> inv [1, 2, 3, 1]
[(3,1)]
if you only need the first element you can get it with map fst.
You can't use zip and tail in this case. This would lead to only comparing consecutive pairs where you need all pairs. So given a list (x:xs), you need to check whether any of the xs is smaller than x:
import Data.Maybe (mapMaybe)
checkInv :: Ord a => a -> a -> Maybe (a,a)
checkInv x y = if x <= y then Nothing
else Just (x, y)
inv :: Ord a => [a] -> [(a,a)]
inv [] = []
inv (x:xs) = mapMaybe (checkInv x) xs ++ inv xs
> inv [1,2,3,1]
[(2,1), (3,1)]
Just to throw some folds into the matter:
inv :: Ord a => [a] -> [(a,a)]
inv [x] = [] :: [(x,x)]
inv xs = foldl (\acc x -> if (head xs) > x then (head xs, x) : acc else acc) [] xs
Zipping and then filtering the pairs is not a bad idea, but you have to consider all the pairs for that to work:
inv xs = filter (\(a, b) -> a > b) $ allPairs xs
where
allPairs xs = allPairsHelp xs (tail xs)
where
allPairsHelp xs [] = []
allPairsHelp xs ys = zip xs ys ++ allPairsHelp xs (tail ys)

Haskell merge sort with two merging functions asc and desc

I would like to make use of the merge sort algorithm. The mergeSort is the main function which awaits the merging function as the first parameter. Does anyone have an idea, where is the issue in my case? Thank you very much in advance.
mergeSort xs = merge xs
mergeDesc xs = reverse (mergeAsc xs)
mergeAsc [] = []
mergeAsc [x] = [x]
mergeAsc xs = merge (mergeAsc top) (mergeAsc bottom) where (top, bottom) = splitAt (length xs `div` 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) | x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
Add type signatures to your functions, then the problem becomes obvious:
mergeAsc, mergeDesc :: Ord a => [a] -> [a]
mergeDesc xs = reverse (mergeAsc xs)
mergeAsc [] = []
mergeAsc [x] = [x]
mergeAsc xs = merge (mergeAsc top) (mergeAsc bottom) where (top, bottom) = splitAt (length xs `div` 2) xs
merge :: Ord a => [a] -> [a] -> [a]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) | x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
So, if you define mergeSort as merge, it's a function that merely merges two ordered lists, when you actually want it to order a single list. You can achieve that with
mergeSort xs = mergeAsc xs
or simply and preferrably,
mergeSort = margeAsc
Note that mergeDesc isn't really nice: you first sort the list in the wrong order, and then reverse it? In Haskell, you want your algorithms to be flexible enough to handle stuff like different orderings by themselves. So you would define
mergeSortBy :: (a->a->Ordering) -> [a] -> [a]
mergeSortBy cmp = mSort
where
mSort [] = []
mSort [x] = [x]
mSort xs = merge (mSort top) (mSort bottom)
where (top, bottom) = splitAt (length xs `quot` 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = case x`cmp`y of
LT -> x : merge xs (y:ys)
_ -> y : merge (x:xs) ys
Then you can simply define mergeSort = mergeSortBy compare, and mergeSortDesc = mergeSortBy (flip compare).
Also observe how making merge a local function prevents the error you had in your implementation.
and it says it should be declared as: mergeSort :: ([a]->[a]->[a]) -> [a] -> [a] as the function that accepts the merging function as the first argument...
That's strange, it shouldn't be called mergeSort then but sortWithMerge or something. Anyway, it's simple enough to do that: just throw out cmp (which is only used in the merge subfunction!) and replace it with merge as an argument instead of defining that locally.
sortWithMerge :: ([a]->[a]->[a]) -> [a] -> [a]
sortWithMerge merger = mSort
where
mSort [] = []
mSort [x] = [x]
mSort xs = merger (mSort top) (mSort bottom)
where (top, bottom) = splitAt (length xs `quot` 2) xs

Simple haskell splitlist

I have the following function which takes a list and returns two sublists split at a given element n. However, I only need to split it in half, with odd length lists having a larger first sublist
splitlist :: [a] -> Int -> ([a],[a])
splitlist [] = ([],[])
splitlist l#(x : xs) n | n > 0 = (x : ys, zs)
| otherwise = (l, [])
where (ys,zs) = splitlist xs (n - 1)
I know I need to change the signature to [a] -> ([a],[a]), but where in the code should I put something like length(xs) so that I don't break recursion?
In a real program you should probably use
splitlist :: [a] -> ([a], [a])
splitlist xs = splitAt ((length xs + 1) `div` 2) xs
(i.e. something along the lines of dreamcrash's answer.)
But if, for learning purposes, you're looking for an explicitly recursive solution, study this:
splitlist :: [a] -> ([a], [a])
splitlist xs = f xs xs where
f (y : ys) (_ : _ : zs) =
let (as, bs) = f ys zs
in (y : as, bs)
f (y : ys) (_ : []) = (y : [], ys)
f ys [] = ([], ys)
You can do it using take and drop:
splitlist :: [a] -> ([a],[a])
splitlist [] = ([],[])
splitlist l = let half = (length(l) +1)`div` 2
in (take half l, drop half l)
or you can take advantage of the function splitAt:
splitlist list = splitAt ((length (list) + 1) `div` 2) list
You can do this by using the take and drop built-in functions. But if you want something that can be done with all self written functions try this:
dropList :: Int -> [Int] -> [Int]
dropList 0 [] = []
dropList 0 (x:xs) = x:xs
dropList y [] = []
dropList y (x:xs) = dropList (y-1) xs
takeList :: Int -> [Int] -> [Int]
takeList 0 [] = []
takeList 0 (x:xs) = []
takeList y [] = []
takeList y (x:xs)
| y <= length (x:xs) = x : takeList (y-1) xs
| otherwise = []
split :: Int -> [Int] -> ([Int],[Int])
split 0 [] = ([],[])
split y [] = ([],[])
split y (x:xs) = (takeList y (x:xs), dropList y (x:xs))
main = do
print (split 4 [1,2,3,4,5,6])

Resources