这里还有另一个因素,在 acfoltzer 包含的一些链接中提到,但在这里可能值得明确说明。您遇到了单态限制的影响。当你说
let x = 5
您对变量进行顶级定义。MR 坚持认为,当没有类型签名的其他定义时,应该通过为未解析的类型变量选择(希望)合适的默认实例来将这些定义专门化为单态值。相比之下,当您使用推断类型时,不会施加此类限制或默认值。所以:t
> :t 3
3 :: (Num t) => t
因为3
确实是重载的:它被任何数字类型所接受。默认规则选择Integer
作为默认数字类型,所以
> let x = 3
> :t x
x :: Integer
但是现在让我们关掉 MR。
> :set -XNoMonomorphismRestriction
> let y = 3
> :t y
y :: (Num t) => t
没有 MR,定义就可以是多态的,就像3
. 只是检查...
> :t y * (2.5 :: Float)
y * (2.5 :: Float) :: Float
> :t y * (3 :: Int)
y * (3 :: Int) :: Int
请注意,根据相关实例提供y = 3
的方法,多态在这些用途中的专业化程度不同。也就是说,与 的特定表示无关,而是与 的表示的构造方案相关联。天真地编译,这是慢的秘诀,有些人认为这是 MR 的动机。fromInteger
Num
y
3
3
在关于单态性限制是更小还是更大的邪恶的辩论中,我(在当地假装是)中立。我总是为顶级定义编写类型签名,因此对于我想要实现的目标没有歧义,而 MR 则无关紧要。
在尝试学习类型系统如何工作时,将类型推断的各个方面分开是非常有用的
'follow the plan',将多态定义专门用于特定用例:一个相当强大的约束解决问题,需要通过回链实现基本统一和实例解析;和
'猜测计划',泛化类型以将多态类型方案分配给没有类型签名的定义:这非常脆弱,而且你越是越过基本的 Hindley-Milner 学科,具有类型类,具有更高级别的多态性,具有GADTs,奇怪的事情变成了。
了解第一个是如何工作的,并理解为什么第二个是困难的,这很好。类型推断中的许多奇怪之处都与第二个有关,并且与单态限制之类的启发式方法有关,它试图在面对歧义时提供有用的默认行为。