Ответ 1
Это действительно замечательный пример; во время компиляции обнаруживается бесконечный цикл. В этом примере нет ничего особенного в выводе Хиндли-Милнера; это происходит как обычно.
Обратите внимание, что 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= [t 4]. Поэтому mergesort должен быть функцией [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]
(Описание выше в терминах логического вывода эквивалентно тому, что делает алгоритм, но конкретная последовательность шагов, которую следует использовать алгоритму, просто такова, например, на странице Википедии.)