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

为什么在Haskell中不推断多态值?,haskell,polymorphism,type-inference,monomorphism-restriction,Haskell,Polymorphism,Type Inference,Monomorphism Restriction,数字文字具有多态类型: *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 :: Num a => a x = 3 ... *Main> :t x x :: (Num

数字文字具有多态类型:

*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 :: Num a => a
x = 3
...
*Main> :t x
x :: (Num a) => a
我可以提供类型签名以确保
x
保持多态性:

f x = 3
...
*Main> :t f
f :: (Num t1) => t -> t1
x :: Num a => a
x = 3
...
*Main> :t x
x :: (Num a) => a
但为什么这是必要的呢?为什么不推断多态类型?

这是一个公式,它说所有值(定义时没有参数且没有显式类型注释)都应该具有单态类型。可以使用
-XNoMonomorphismRestriction
在ghc和ghci中禁用此限制

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

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

x = longCalculation 42

main = print $ x + x

对sepp2k的答案进行一点扩展:如果您试图编译以下内容(或将其加载到GHCi中),您将得到一个错误:

import Data.List (sort)
f = head . sort
这违反了单态限制,因为我们有一个类约束(由
sort
引入),但没有显式参数:我们(有点神秘地)被告知约束
Ord a
中有一个
不明确的类型变量

您的示例(
let x=3
)有一个类似的不明确类型变量,但它没有给出相同的错误,因为它由以下方式保存:

任何单态类型变量 当类型推断为 整个模块都完成了,是吗 被认为是不明确的,并已解决 使用 违约规则(第4.3.4节)

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

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

default (Int, Rational)

这会有什么不同吗?(我真的不知道,尽管我怀疑不知道)这确实有区别;我希望类型尽可能保持通用。再来吗?无论
x
Integer
还是
Num a=>a
,都可以将其传递给任何需要
Num
的函数。函数必须是泛型的,而值不是。@delnan:但是你不能将它传递给一个需要
Int
@sepp2k:Ah的函数,这是缺少的部分。谢谢。啊,是的,可怕的单态限制。。。我听说过这件事,但从未仔细研究过到底是什么。谢谢若我给它添加了显式类型签名,它还会被计算两次吗?并没有单态限制扩展?@JustinL若它有多态类型,它会被计算两次。如果它是单态的,它不会。单态性限制只影响它是否将获得无注释的单态或多态类型。如果添加注释,单态限制没有什么区别。为什么它不能为每种类型计算和存储它呢?@praxeotic
x::T1
x::T2
(其中T1和T2是
Num
的不同实例)是不同的事情(它们会有不同的类型和内存表示,甚至可能在语义上有不同的值),因此您不能只将它们存储为单个值。因此,
x
需要作为函数实现(将所需的实例作为参数)。理论上,该函数可以缓存每个实例的结果(因此
(x::T1,x::T2,x::T2)
将导致两次计算,而不是三次计算,但GHC不会这样做。当我将
f=head.sort
放入一个文件并尝试加载它时,我会得到一个错误,但当我在GHCi中键入
let f=head.sort
时,我不会得到错误,并且生成的绑定具有以下类型:
f:[()]->()
。这是怎么回事???@pelotom:这是因为GHCi的。