为什么 Haskell 中不推断多态值?

发布于 2024-10-02 05:46:03 字数 463 浏览 1 评论 0原文

数字文字具有多态类型:

*Main> :t 3
3 :: (Num t) => t

但是,如果我将变量绑定到这样的文字,则多态性就会丢失:

x = 3
...
*Main> :t x
x :: Integer

另一方面,如果我定义一个函数,它当然是多态的:

f x = 3
...
*Main> :t f
f :: (Num t1) => t -> t1

我可以提供类型签名来确保 < code>x 仍然是多态的:

x :: Num a => a
x = 3
...
*Main> :t x
x :: (Num a) => a

但是为什么这是必要的呢?为什么不推断多态类型?

Numeric literals have a polymorphic type:

*Main> :t 3
3 :: (Num t) => t

But if I bind a variable to such a literal, the polymorphism is lost:

x = 3
...
*Main> :t x
x :: Integer

If I define a function, on the other hand, it is of course polymorphic:

f x = 3
...
*Main> :t f
f :: (Num t1) => t -> t1

I could provide a type signature to ensure the x remains polymorphic:

x :: Num a => a
x = 3
...
*Main> :t x
x :: (Num a) => a

But why is this necessary? Why isn't the polymorphic type inferred?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

原谅我要高飞 2024-10-09 05:46:03

这是单态限制,它表示所有不带参数定义的值并且不具有显式类型注释应该具有单态类型。可以使用 -XNoMonomorphismRestriction 在 ghc 和 ghci 中禁用此限制。

限制的原因是,如果没有此限制,long_calculation 42 将被评估两次,而大多数人可能期望/希望它只被评估一次:

longCalculation :: Num a => a -> a
longCalculation = ...

x = longCalculation 42

main = print $ x + x

It's the monomorphism restriction which says that all values, which are defined without parameters and don't have an explicit type annotation, should have a monomorphic type. This restriction can be disabled in ghc and ghci using -XNoMonomorphismRestriction.

The reason for the restriction is that without this restriction long_calculation 42 would be evaluated twice, while most people would probably expect/want it to only be evaluated once:

longCalculation :: Num a => a -> a
longCalculation = ...

x = longCalculation 42

main = print $ x + x
べ映画 2024-10-09 05:46:03

稍微扩展一下 sepp2k 的答案:如果您尝试编译以下内容(或将其加载到 GHCi 中),则会收到错误:

import Data.List (sort)
f = head . sort

这违反了单态性限制,因为我们有一个类约束(由 sort< 引入) /code>),但没有明确的参数:我们(有点神秘地)被告知,在约束 Ord a 中有一个不明确的类型变量

您的示例 (let x = 3) 具有类似的不明确类型变量,但它不会给出相同的错误,因为它是由 Haskell 的“默认”规则

任何单态类型变量
当类型推断时保留
整个模块完成了,是
被认为不明确,并得到解决
使用特定类型
默认规则(第 4.3.4 节)。

有关默认规则的更多信息,请参阅此答案 - 重要的一点是它们仅适用于某些数字类,因此 x = 3 可以,而 f = sort 则不行。

附带说明:如果您希望 x = 3 最终成为 Int 而不是 Integer,并且 y = 3.0 是一个 Rational 而不是 Double,您可以使用“默认声明”来覆盖默认的默认规则:

default (Int, Rational)

To expand on sepp2k's answer a bit: if you try to compile the following (or load it into GHCi), you get an error:

import Data.List (sort)
f = head . sort

This is a violation of the monomorphism restriction because we have a class constraint (introduced by sort) but no explicit arguments: we're (somewhat mysteriously) told that we have an Ambiguous type variable in the constraint Ord a.

Your example (let x = 3) has a similarly ambiguous type variable, but it doesn't give the same error, because it's saved by Haskell's "defaulting" rules:

Any monomorphic type variables that
remain when type inference for an
entire module is complete, are
considered ambiguous, and are resolved
to particular types using the
defaulting rules (Section 4.3.4).

See this answer for more information about the defaulting rules—the important point is that they only work for certain numeric classes, so x = 3 is fine while f = sort isn't.

As a side note: if you'd prefer that x = 3 end up being an Int instead of an Integer, and y = 3.0 be a Rational instead of a Double, you can use a "default declaration" to override the default defaulting rules:

default (Int, Rational)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文