为什么 3 和 x(被分配为 3)在 Haskell 中具有不同的推断类型?
Haskell 中的类型推断有一点学习曲线(至少可以这么说!)。开始学习它的一个好方法是通过简单的例子。因此,以下是类型推断的“hello world”。
考虑以下示例:
Prelude> :t 3
3 :: (Num t) => t
Prelude> let x = 3
Prelude> :t x
x :: Integer
问题是:为什么 3 和 x 有不同的类型?
链接摘要:
阅读下面的答案以了解完整的故事;这里只是一个链接摘要:
- GHC 类型默认: Haskell Report 部分 4.3.4
- GHCi 的扩展类型默认:使用 GHCi 部分 2.4.5
- 单态限制: Haskell 维基百科
Type inference in Haskell has a bit of a learning curve (to say the least!). A good way to start learning it is with simple examples. So, the following is a bit of a "hello world" for type inference.
Consider the following example:
Prelude> :t 3
3 :: (Num t) => t
Prelude> let x = 3
Prelude> :t x
x :: Integer
The question is thus: Why do 3 and x have different types?
Link Summary:
Read the answers below for the full story; here's just a link summary:
- GHC type defaulting: Haskell Report section
4.3.4 - GHCi's extended type defaulting: Using GHCi section
2.4.5 - Monomorphic Restriction: Haskell
wiki
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这里还有另一个因素,在 acfoltzer 包含的一些链接中提到过,但可能值得在这里明确说明。您遇到了单态限制的影响。当您说
您对变量进行顶级定义时。 MR 坚持认为,当这些定义没有类型签名时,应该通过为未解析的类型变量选择(希望)合适的默认实例来专门化为单态值。相比之下,当您使用
:t
请求推断类型时,不会施加此类限制或默认值。因为3
确实是重载的:任何数字类型都承认它。默认规则选择Integer
作为默认数字类型,所以现在让我们关闭 MR。
如果没有 MR,定义就尽可能多态,就像
3
一样重载。只是检查...请注意,根据相关
Num
fromInteger 方法,多态y = 3
在这些用途中的专门化有所不同> 实例。也就是说,y
并不与3
的特定表示相关联,而是与用于构造3
的表示的方案相关联。天真的编译,这是缓慢的秘诀,一些人将其视为 MR 的动机。对于单态限制是大恶还是小恶的争论,我(局部假装)保持中立。我总是为顶级定义编写类型签名,因此我想要实现的目标没有任何歧义,并且 MR 不是重点。
当尝试学习类型系统如何工作时,将类型推断的各个方面分开非常有用,
“遵循计划”,将多态定义专门针对特定用例:一个相当强大的约束解决问题,需要基本统一以及通过回链进行实例解析;
“猜测计划”,泛化类型以将多态类型方案分配给没有类型签名的定义:这是非常脆弱的,并且越多地越过基本的 Hindley-Milner 规则,具有类型类,具有更高的-等级多态性,有了 GADT,事情就变得更奇怪了。
了解第一个方法是如何运作的,并了解为什么第二个方法很困难,这是很好的做法。类型推断中的许多奇怪之处都与第二个相关,并且与诸如单态限制之类的启发式方法相关,这些启发式方法试图在面对歧义时提供有用的默认行为。
There's another factor here, mentioned in some of the links which acfoltzer includes, but it might be worth making explicit here. You're encountering the effect of the monomorphism restriction. When you say
you make a top-level definition of a variable. The MR insists that such definitions, when otherwise unaccompanied by a type signature, should be specialized to a monomorphic value by choosing (hopefully) suitable default instances for the unresolved type variables. By contrast, when you use
:t
to ask for an inferred type, no such restriction or defaulting is imposed. Sobecause
3
is indeed overloaded: it is admitted by any numeric type. The defaulting rules chooseInteger
as the default numeric type, soBut now let's switch off the MR.
Without the MR, the definition is just as polymorphic as it can be, just as overloaded as
3
. Just checking...Note that the polymorphic
y = 3
is being differently specialized in these uses, according to thefromInteger
method supplied with the relevantNum
instance. That is,y
is not associated with a particular representation of3
, but rather a scheme for constructing representations of3
. Naïvely compiled, that's a recipe for slow, which some people cite as a motivation for the MR.I'm (locally pretending to be) neutral on the debate about whether the monomorphism restriction is a lesser or greater evil. I always write type signatures for top-level definitions, so there is no ambiguity about what I'm trying to achieve and the MR is beside the point.
When trying to learn how the type system works, it's really useful to separate the aspects of type inference which
‘follow the plan’, specializing polymorphic definitions to particular use cases: a fairly robust matter of constraint-solving, requiring basic unification and instance resolution by backchaining; and
‘guess the plan’, generalizing types to assign a polymorphic type scheme to a definition with no type signature: that's quite fragile, and the more you move past the basic Hindley-Milner discipline, with type classes, with higher-rank polymorphism, with GADTs, the stranger things become.
It's good to learn how the first works, and to understand why the second is difficult. Much of the weirdness in type inference is associated with the second, and with heuristics like the monomorphism restriction trying to deliver useful default behaviour in the face of ambiguity.
出现这种情况是因为 GHCi 中的默认类型,如所讨论的此处,这里,此处,以及这里,等等。不幸的是,这似乎很难搜索,因为在您知道“类型默认”这个短语之前,有很多方法可以描述这种行为。
更新:哦。删除了不好的例子。
This occurs because of type defaulting in GHCi, as discussed here, here, here, and here, among others. Unfortunately this seems like something that is difficult to search for, since there are lots of ways to describe this behavior before you know the phrase "type defaulting".
Update: D'oh. Removed poor example.
由于没有其他人提到为什么存在单态限制,我想我应该添加Haskell 的历史:对类的懒惰。
我发现这篇论文对单态限制的基调非常有趣。
Since nobody else has mentioned why there's a monomorphism restriction, I thought I'd add this bit from A History of Haskell: Being Lazy With Class.
I find the tone of the paper towards the monomorphism restriction is very interesting.