首页 文章

Haskell中的succ:模糊类型变量[重复]

提问于
浏览
0

这个问题在这里已有答案:

我想编写一个函数mapsucc,它生成列表中每个项目的后继 . 很容易:

mapsucc xs = map succ xs

工作得很好 . 我想我可以使用Currying来使这个定义更短:

mapsucc = map succ

但我得到:

No instance for (Enum b0) arising from a use of ‘succ’
The type variable ‘b0’ is ambiguous
Relevant bindings include
  mapsucc :: [b0] -> [b0] (bound at mapsucc.hs:1:1)
Note: there are several potential instances:
  instance Enum Ordering -- Defined in ‘GHC.Enum’
  instance Enum Integer -- Defined in ‘GHC.Enum’
  instance Enum () -- Defined in ‘GHC.Enum’
  ...plus six others
In the first argument of ‘map’, namely ‘succ’
In the expression: map succ
In an equation for ‘mapsucc’: mapsucc = map succ

现在,我不清楚为什么curried版本应该是模糊的,相反,为什么具有显式参数的那个不是 .

另外,如果从ghci我使用let声明mapsucc,它可以完美地工作:

Prelude> let mapsucc = map succ
Prelude> mapsucc "hello"
"ifmmp"

如果我重新定义succ,行为相同:

mysucc x = succ x

完美,但同时

mysucc = succ

给出了同样的错误:

No instance for (Enum a0) arising from a use of ‘succ’
The type variable ‘a0’ is ambiguous
Relevant bindings include
  mysucc :: a0 -> a0 (bound at mapsucc.hs:3:1)
Note: there are several potential instances:
  instance Enum Ordering -- Defined in ‘GHC.Enum’
  instance Enum Integer -- Defined in ‘GHC.Enum’
  instance Enum () -- Defined in ‘GHC.Enum’
  ...plus six others
In the expression: succ
In an equation for ‘mysucc’: mysucc = succ

而且,如果我通过let定义了ghci中的mysucc,它可以完美地运行:

Prelude> let mysucc = succ
Prelude> mysucc 3
4

2 回答

  • 5

    像你之前的许多人一样,你被可怕的单态限制所困扰 . 对此的规则大致如下:

    • 如果值具有显式参数,那么它将以您期望的方式自动变为多态 . 这就是你的第一个版本有效的原因:它有类型

    mapsucc :: Enum b => [b] - > [b]

    • 在ghc(但不是ghci)中,如果值没有显式参数(比如你的第二个版本),那么它不是多态的 . 所以ghc试图找出 b 是什么类型,并发现它不能 . 因此错误消息 .

    • 在ghci中没有单态限制,所以你的第二个例子在那里工作,它与第一个有相同的类型 .

    有关详细信息,包括对此规则存在的原因的解释,see here .

  • 3

    你正在遇到所谓的单态限制 .

    较新的GHC版本提供稍微更好的错误消息:

    test.hs:1:9: error:
        • Ambiguous type variable ‘b0’ arising from a use of ‘succ’
          prevents the constraint ‘(Enum b0)’ from being solved.
          Relevant bindings include f :: [b0] -> [b0] (bound at test.hs:1:1)
          Probable fix: use a type annotation to specify what ‘b0’ should be.
          These potential instances exist:
            instance Enum Ordering -- Defined in ‘GHC.Enum’
            instance Enum Integer -- Defined in ‘GHC.Enum’
            instance Enum () -- Defined in ‘GHC.Enum’
            ...plus six others
            ...plus two instances involving out-of-scope types
            (use -fprint-potential-instances to see them all)
        • In the first argument of ‘map’, namely ‘succ’
          In the expression: map succ
          In an equation for ‘f’: f = map succ
      |
    1 | f = map succ
      |         ^^^^
    

    正如您所看到的,这里它直接给出了写一个类型签名的建议,这在这里确实是正确的解决方案 .

相关问题