为什么在Haskell中没有推断出多态值?

Tom*_*ett 21 polymorphism haskell type-inference monomorphism-restriction

数字文字具有多态类型:

*Main> :t 3
3 :: (Num t) => t
Run Code Online (Sandbox Code Playgroud)

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

x = 3
...
*Main> :t x
x :: Integer
Run Code Online (Sandbox Code Playgroud)

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

f x = 3
...
*Main> :t f
f :: (Num t1) => t -> t1
Run Code Online (Sandbox Code Playgroud)

我可以提供一个类型签名,以确保x遗骸多态:

x :: Num a => a
x = 3
...
*Main> :t x
x :: (Num a) => a
Run Code Online (Sandbox Code Playgroud)

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

sep*_*p2k 23

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

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

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

x = longCalculation 42

main = print $ x + x
Run Code Online (Sandbox Code Playgroud)


Tra*_*own 19

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

import Data.List (sort)
f = head . sort
Run Code Online (Sandbox Code Playgroud)

这是对单同性限制的违反,因为我们有一个类约束(由引入sort)但没有明确的参数:我们(有点神秘地)告诉我们Ambiguous type variable在约束中有一个Ord a.

你的example(let x = 3)有一个类似的模糊类型变量,但它没有给出相同的错误,因为它是由Haskell的"默认"规则保存的:

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

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

作为一个方面说明:如果您不希望x = 3最终成为一个Int替代的Integer,并且y = 3.0是一个Rational,而不是一个Double,可以使用"默认的声明",以覆盖缺省默认的规则:

default (Int, Rational)
Run Code Online (Sandbox Code Playgroud)

  • @pelotom:这是因为GHCi的[扩展默认规则](http://www.haskell.org/ghc/docs/6.12.2/html/users_guide/interactive-evaluation.html#extended-default-rules). (2认同)