Search code examples
listhaskellmergesortingsortedlist

Merge two sorted lists in Haskell- what is the difference between these Algorithms


I try to understand, what's the difference between the second two algorithms.

The first one (merge) works well, but when I try to convert the algorithm to Guarded notation (merge') I get a "Non-exhaustive patterns ..." exception.

But why is the third version (merge'') working? It is almost the same like merge', there has to be something with the list (x:xs) that I don't understand.

   1 -- merges two sortedists                                        
   2 merge xs [] = xs
   3 merge [] ys = ys
   4 merge (x:xs) ys
   5     | x <= head ys = x : (merge xs ys)
   6     | otherwise = head ys : (merge (x:xs) (tail ys))
   7     
   8 -- merges two sorted lists (fails with exception)
   9 merge' z@(x:xs) ys
  10     | ys == [] = z
  11     | z == []  = ys
  12     | x <= head ys = x : (merge' xs ys)
  13     | otherwise = head ys : (merge' (x:xs) (tail ys))
  14     
  15 
  16 -- merges two sorted lists (exept the last element of the first list)
  17 merge'' z@(x:xs) ys
  18     | ys == [] = z
  19     | xs == []  = ys
  20     | x <= head ys = x : (merge'' xs ys)
  21     | otherwise = head ys : (merge'' (x:xs) (tail ys))

Solution

  • In merge' and merge'' you assume the first argument to be of the form x:xs, this excludes the empty list, and is causing the problems.

    For example

    head z@(x:xs) = x
    

    will produce 1 as expected when calling head([1,2,3]), but head([]) will throw a Non-exhaustive patterns in function head exception because [] does not match x:xs (the @ is not really important here).

    In particular, this means that in merge' the z == [] case can never be matched and also merge'' will throw an exception if you call merge [] [1,2,3] for example.

    Also note that in merge'' the case xs == [] is problematic. If, for example, we call merge'' [1] [2], then this case is matched because [1] is 1:[]. Then, just ys, i.e., [2] is returned and the x, which is 1, gets lost.