Это действительно замечательный пример; бесконечный цикл обнаруживается, по существу, в время компиляции ! В этом примере нет ничего особенного в выводе Хиндли-Милнера; это просто происходит как обычно.
Обратите внимание, что ghc правильно получает типы split
и merge
:
*Main> :t split
split :: [a] -> ([a], [a])
*Main> :t merge
merge :: (Ord t) => [t] -> [t] -> [t]
Теперь, когда дело доходит до mergesort
, это, вообще говоря, функция t 1 → t 2 для некоторых типов t 1 и t 2 . Затем он видит первую строку:
mergesort [] = []
и понимает, что t 1 и t 2 должны быть типами списка, скажем, t 1 = [t 3 ] и t 2 * 1 031 * = [т * 1 032 * 4 * 1 033 *]. Таким образом, сортировка слиянием должна быть функцией [t 3 ] → [t 4 ]. Следующая строка
mergesort xs = merge (mergesort p) (mergesort q)
where (p,q) = split xs
говорит, что:
- xs должен быть входом для разбиения, т. Е. Типа [a] для некоторого a (что уже есть для a = t 3 ).
- То есть
p
и q
также имеют тип [t 3 ], поскольку split
- это [a] → ([a], [a])
mergesort p
, поэтому (напомним, что сортировка слиянием, как полагают, имеет тип [t 3 ] → [t 4 ]) имеет тип [t 4 ].
mergesort q
относится к типу [t 4 ] по той же причине.
- Поскольку
merge
имеет тип (Ord t) => [t] -> [t] -> [t]
, а оба входа в выражении merge (mergesort p) (mergesort q)
имеют тип [t 4 ], тип t 4 должен быть в Ord
.
- Наконец, тип
merge (mergesort p) (mergesort q)
совпадает с обоими его входами, а именно [t 4 ]. Это соответствует ранее известному типу [t 3 ] → [t 4 ] для mergesort
, так что больше нет выводов, которые нужно сделать, и часть "объединения" Алгоритм Хиндли – Милнера завершен. mergesort
имеет тип [t 3 ] → [t 4 ] с t 4 в Ord
.
Вот почему вы получаете:
*Main> :t mergesort
mergesort :: (Ord a) => [t] -> [a]
(Вышеприведенное описание в терминах логического вывода эквивалентно тому, что делает алгоритм, но конкретная последовательность шагов, за которыми следует алгоритм, просто приведена, например, на странице Википедии.)