Haskell中的succ:模糊类型变量

时间:2018-05-15 15:59:21

标签: haskell

我想编写一个函数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

现在,我不清楚为什么咖喱版应该含糊不清,为什么显而易见的参数不是。

另外,如果从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 个答案:

答案 0 :(得分:5)

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

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

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

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

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

有关详细信息,包括此规则存在原因的说明,see here

答案 1 :(得分: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
  |         ^^^^

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