4

我最近开始玩 haskell,在使用 HashMap 时遇到了一个问题,这个玩具示例可以说明这一点:

import Data.HashMap as HashMap

foo = HashMap.insert 42 53 HashMap.empty

这是我在解释器中加载文件或编译文件时遇到的错误:

Prelude List HashMap> :load TypeError.hs
[1 of 1] Compiling Main             ( TypeError.hs, interpreted )

TypeError.hs:3:22:
    Ambiguous type variable `k0' in the constraints:
      (Num k0) arising from the literal `42' at TypeError.hs:3:22-23
      (Ord k0) arising from a use of `insert' at TypeError.hs:3:7-20
      (Data.Hashable.Hashable k0)
        arising from a use of `insert' at TypeError.hs:3:7-20
    Possible cause: the monomorphism restriction applied to the following:
      foo :: Map k0 Integer (bound at TypeError.hs:3:1)
    Probable fix: give these definition(s) an explicit type signature
                  or use -XNoMonomorphismRestriction
    In the first argument of `insert', namely `42'
    In the expression: insert 42 53 empty
    In an equation for `foo': foo = insert 42 53 empty
Failed, modules loaded: none.
Prelude List HashMap>

但是,如果我直接在解释器中定义完全相同的函数,则不会出现错误:

Prelude List HashMap> let foo = HashMap.insert 42 53 HashMap.empty
Prelude List HashMap>

有人对此有任何线索吗?

谢谢。

4

1 回答 1

6

原因是 ghci 使用扩展的默认规则,而编译器(默认)使用语言报告中指定的默认规则

Num 类中的歧义是最常见的,因此 Haskell 提供了另一种解决它们的方法——使用默认声明:default (t1 , ... , tn) 其中 n ≥ 0,并且每个 ti 必须是 Num ti 持有的类型。在发现不明确类型的情况下,不明确类型变量 v 在以下情况下是可默认的:

  • v 仅出现在 C v 形式的约束中,其中 C 是一个类,并且
  • 这些类中至少有一个是数字类(即 Num 或 Num 的子类),并且
  • 所有这些类都在 Prelude 或标准库中定义

相关规则是,仅当所有涉及的类都在标准库中定义时,才会根据报告进行默认设置,但Hashable对键的约束涉及不满足该要求的类。

因此编译器拒绝它,因为它无法解析由键引起的模棱两可的类型变量,而 ghci 将其默认为Integer,因为如果涉及其他类,ghci 也会默认。

于 2012-12-06T20:42:08.987 回答