Este algoritmo segue uma estratégia chamada de “divisão e conquista”.

  1. Quando a lista tem mais do que um elemento, parte-se a lista em duas listas de tamanho aproximadamente igual (podem diferir em uma unidade).
  2. Depois ordenam-se estas listas mais pequenas pelo mesmo método
  3. Finalmente faz-se a fusão das duas listas ordenadas de forma a que a lista final fique ordenada

-- Passo 3 com a função merge
merge :: (Ord a) => [a] -> [a] -> [a]
merge [] l = l
merge l [] = l
merge (x:xs) (y:ys) | x<y = x : merge xs (y:ys)
                    | otherwise = y : merge (x:xs) ys

-- Passo 1 e 2 com a função msort
msort :: (Ord a) => [a] -> [a]
msort [x] = [x]
msort l = merge (msort l1) (msort l2)
    where n = (length l) `div` 2
          (l1,l2) = SplitAt n l

-- Outra maneira para o passo 1 e 2
-- Split parte a lista numa só travessia. A lista está ser partida de maneira 
-- diferente, mas isso não tem interferência no algoritmo.
split :: [a] -> ([a],[a])
split [] = ([],[])
split [x] = ([x],[])
split (x:y:t) = (x:l1, y:l2)
 where (l1,l2) = split t

msort :: (Ord a) => [a] -> [a]
msort [] = []
msort [x] = [x]
msort l = merge (msort l1) (msort l1)
 where (l1,l2) = split l

nome**@**padrão

É uma forma de fazer uma definição local ao nível de um argumento de uma função.

merge :: (Ord a) => [a] -> [a] -> [a]
merge [] l = l
merge l [] = l
merge **a@**(x:xs) **b@**(y:ys) | x < y = x : merge xs **b**
 | otherwise = y : merge **a** ys