2

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

1 Answer 1

5

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
Sign up to request clarification or add additional context in comments.

5 Comments

It helped thank you very much, the last thing I need to know, that when I set the type signature of my mergeSort function to: mergeSort :: ([a]->[a]->[a]) -> [a] -> [a] it is a type error in the application... how to solve that? those two type declarations must be the way you and I defined it. Thank you so far @leftaroundabout :)
Why do you think it should be ([a]->[a]->[a]) -> [a] -> [a]?
Because I have a specific task to accomplish, 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... and two separate merging functions that order the values ascending and descending, as it is "shown" in my solution, and those two functions should be declared as: Ord a => [a] -> [a]
The task says: Write a mergeSort (merge sorting) function, which awaits the merging function as the first parameter. mergeSort :: ([a]->[a]->[a]) -> [a] -> [a] Write two additional merging functions, which will order the values ascending/descending mergeDesc :: Ord a => [a] -> [a] -> [a] mergeAsc :: Ord a => [a] -> [a] -> [a]
@baron ok... though as I said this shouldn't be called mergeSort then. As for mergeAsc and mergeDesc, I would again implement those as specialisations of a common mergeGen :: (a->a->Ordering) -> [a]->[a]->[a], as mergeAsc = mergeGen compare and mergeDesc = mergeGen $ flip compare.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.