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

数字文字具有多态类型:

*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

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


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

限制的原因是没有这个限制, long_calculation 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有一个Ambiguous type variable

你的例子( let x = 3 )有一个类似含糊的类型变量,但它不会给出相同的错误,因为它是由Haskell的“默认”规则保存的:

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

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

作为一个方面说明:如果你希望x = 3最终是一个Int而不是Integery = 3.0是一个Rational而不是Double ,那么可以使用“默认声明”来覆盖默认的默认规则:

default (Int, Rational)
链接地址: http://www.djcxy.com/p/43085.html

上一篇: Why are polymorphic values not inferred in Haskell?

下一篇: How to create a polyvariadic haskell function?