22

数值字面量具有多态类型:

*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

我可以提供一个类型签名来确保x保持多态:

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

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

4

2 回答 2

23

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

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

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

x = longCalculation 42

main = print $ x + x
于 2010-11-14T20:24:34.967 回答
19

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

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

这违反了单态限制,因为我们有一个类约束(由 引入sort)但没有明确的参数:我们(有点神秘地)被告知我们有一个Ambiguous type variablein 约束Ord a

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

当整个模块的类型推断完成时保留的任何单态类型变量都被认为是模棱两可的,并使用默认规则(第 4.3.4 节)解析为特定类型。

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

作为旁注:如果您希望x = 3最终成为 a 而Int不是a Integer,并且y = 3.0是 aRational而不是 a Double,您可以使用“默认声明”来覆盖默认的默认规则:

default (Int, Rational)
于 2010-11-14T22:17:42.247 回答