在 Andrew Koenig 的关于 ML 类型推断的轶事中,作者使用归并排序的实现作为 ML 的学习练习,并且很高兴发现“不正确”的类型推断。
令我惊讶的是,编译器报告了一种
'a list -> int list
换句话说,这个排序函数接受任何类型的列表并返回一个整数列表。
那是不可能的。输出必须是输入的排列;它怎么可能有不同的类型?读者肯定会发现我的第一个冲动很熟悉:我想知道我是否在编译器中发现了一个错误!
再想一想,我意识到还有另一种方法可以让函数忽略它的参数:也许它有时根本不返回。事实上,当我尝试它时,这正是发生的事情:
sort(nil)
确实 returnnil
,但是对任何非空列表进行排序都会进入无限递归循环。
翻译成 Haskell 时
split [] = ([], [])
split [x] = ([x], [])
split (x:y:xs) = (x:s1, y:s2)
where (s1,s2) = split xs
merge xs [] = xs
merge [] ys = ys
merge xx@(x:xs) yy@(y:ys)
| x < y = x : merge xs yy
| otherwise = y : merge xx ys
mergesort [] = []
mergesort xs = merge (mergesort p) (mergesort q)
where (p,q) = split xs
GHC 推断出类似的类型:
*Main> :t mergesort
mergesort :: (Ord a) => [t] -> [a]
Damas-Hindley-Milner 算法如何推断这种类型?