2

我在 ghci 7.6.3 中尝试了以下内容

prelude> let m = map

以上工作。GHCi 没有错误。

但后来我尝试了,

prelude> let r = read

上面的代码在 GHCi 中抛出了一个大错误。这是我得到的错误,

*Main> let r = read

<interactive>:122:9:
    No instance for (Read a0) arising from a use of `read'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Read IOMode -- Defined in `GHC.IO.IOMode'
      instance Read BufferMode -- Defined in `GHC.IO.Handle.Types'
      instance Read Newline -- Defined in `GHC.IO.Handle.Types'
      ...plus 30 others
    In the expression: read
    In an equation for `r': r = read

然后我尝试了,

prelude> let r = read :: Read a => String -> a

认为类型签名可能会解决问题。但话又说回来,我从 GHCi 收到了一个错误。确切的错误如下,

*Main> let r = read :: Read a => String -> a

<interactive>:123:9:
    No instance for (Read a0) arising from an expression type signature
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Read IOMode -- Defined in `GHC.IO.IOMode'
      instance Read BufferMode -- Defined in `GHC.IO.Handle.Types'
      instance Read Newline -- Defined in `GHC.IO.Handle.Types'
      ...plus 30 others
    In the expression: read :: Read a => String -> a
    In an equation for `r': r = read :: Read a => String -> a
*Main> 

有人可以告诉我发生了什么吗?

谢谢。

4

1 回答 1

7

这是单态限制的一个例子。默认情况下,您不允许绑定这样的多态值,因为它的值看起来r应该只计算一次,但实际上每次调用时都会重新计算。

在这种情况下,read是多态的,因为它有一个隐式参数用于传递类型类的字典Read,因此r每次都需要重新计算。map是单态的,因为它没有任何类型类限制。

如果你把它写成

let r x = read x

将被允许​​。

您还可以添加非多态类型签名:

let r = read :: String -> Int

这允许它r为 的单个实例计算单个时间Read

带有类型签名的普通声明也不受单态限制,所以如果你这样写,它将被允许。

r :: Read a => String -> a
r = read

-XNoMonomorphismRestriction您也可以使用选项或添加{-# LANGUAGE NoMonomorphismRestriction #-}到文件顶部简单地关闭单态限制。通常认为这样做是安全的,尽管它可能会对性能产生负面影响。

于 2013-06-24T13:15:06.623 回答