【问题标题】:Why are polymorphic values not inferred in Haskell?为什么在 Haskell 中没有推断出多态值?
【发布时间】:2011-05-09 22:20:18
【问题描述】:

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

*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

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

【问题讨论】:

  • 会有什么不同吗? (我真的不知道,虽然我怀疑不是)
  • 它确实有所作为;我希望类型尽可能通用。
  • 再来?无论xInteger 还是Num a => a,您都可以将它传递给任何需要Num 的函数。函数必须是通用的,值不是。
  • @delnan:但您不能将它传递给需要 Int 的函数。
  • @sepp2k:啊,那是缺失的部分。谢谢。

标签: haskell polymorphism type-inference monomorphism-restriction


【解决方案1】:

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

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

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

x = longCalculation 42

main = print $ x + x

【讨论】:

  • 啊,是的,可怕的单态限制......我听说过这个,但从来没有研究过它到底是什么。谢谢!
  • 如果我为此添加了显式类型签名,它是否仍会被评估两次,并且没有单态限制扩展?
  • @JustinL 如果它具有多态类型,它将被评估两次。如果它具有单态类型,则不会。单态性限制只影响它是否会获得没有注释的单态或多态类型。如果添加注解,单态限制没有区别。
  • 为什么不能只为每种类型评估和存储它?
  • @Praxeolitic x :: T1x :: T2(其中 T1 和 T2 是 Num 的不同实例)是不同的东西(它们具有不同的类型和内存表示,甚至可能在语义上具有不同的值) ,因此您不能只将它们存储为单个值。所以x 需要实现为一个函数(将所需的实例作为参数)。从理论上讲,该函数可以缓存每个实例的结果(因此(x :: T1, x :: T2, x :: T2) 将导致两次计算而不是三次计算,但 GHC 不会这样做。
【解决方案2】:

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

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

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

您的示例 (let x = 3) 具有类似的模棱两可的类型变量,但它不会给出相同的错误,因为它是由 Haskell's "defaulting" rules 保存的:

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

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

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

default (Int, Rational)

【讨论】:

  • 当我将f = head . sort 放入一个文件并尝试加载它时,我得到一个错误,但是当我在 GHCi 中输入let f = head . sort 时我没有收到任何错误,并且生成的绑定具有这种类型: f :: [()] -> ()。那是怎么回事??
  • @pelotom:因为 GHCi 的extended default rules
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 2019-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多