0

我正在尝试编译简单的代码片段。

main = (putStrLn . show) (Right 3.423)

编译导致以下错误:

No instance for (Show a0) arising from a use of `show'
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 Show Double -- Defined in `GHC.Float'
  instance Show Float -- Defined in `GHC.Float'
  instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
    -- Defined in `GHC.Real'
  ...plus 42 others
In the second argument of `(.)', namely `show'
In the expression: putStrLn . show
In the expression: (putStrLn . show) (Right 3.423)

当我从 ghci 执行相同的代码段时,一切都按预期工作。

Prelude> let main = (putStrLn . show) (Right 3.423)
Prelude> main
Right 3.423

所以问题是发生了什么?

4

1 回答 1

6

问题是 GHC 无法确定完整的类型Right 3.423是什么,它只能确定它有 type ,而forEither a Double的实例看起来像。如果没有对 的额外限制,GHC 不知道如何打印它。ShowEitherinstance (Show a, Show b) => Show (Either a b)Either a Double

它在交互模式下工作的原因是可怕的单态限制,这使得 GHCi 在它选择的默认值中更具侵略性。这可以用 禁用:set -XNoMonomorphismRestriction,这将成为 GHC 未来版本的默认设置,因为它会给初学者带来很多问题。

这个问题的解决方案是Right 3.423在你的源代码中添加一个类型签名,比如

main = (putStrLn . show) (Right 3.423 :: Either () Double)

这里我只使用()了 for a,因为无论如何我们都不关心它,它是可以显示的“最简单”的类型。你可以放Stringor Intor Doubleor 任何你想要的东西,只要它实现Show.

提示,putStrLn . show正是 的定义print,所以你可以这样做

main = print (Right 3.423 :: Either () Double)


正如@ØrjanJohansen 指出的那样,这不是单态限制,而是ExtendedDefaultRulesGHCi 使用的扩展,它基本上完成了我在上面所做的工作,并()插入类型变量以使交互会话中工作。

于 2014-06-12T13:55:19.830 回答