编译打印时出错任何一个值

时间:2014-06-12 13:50:24

标签: haskell either

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

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

所以问题是发生了什么?

1 个答案:

答案 0 :(得分:6)

<击> 问题是GHC无法确定完整类型的Right 3.423是什么,它只能确定它具有Either a Double类型,Show的实例是Either看起来像instance (Show a, Show b) => Show (Either a b)。如果没有Either a Double的额外约束,GHC就不知道如何打印它。

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

此问题的解决方案是在源代码中的Right 3.423上添加类型签名,例如

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

这里我刚刚使用()作为a,因为我们无论如何都不关心它,它是可以显示的“最简单”类型。您可以将StringIntDouble或其他任何内容放在那里,只要它实现Show

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

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

<击>


正如@ØrjanJohansen指出的那样,这不是单态限制,而是GHCi使用的ExtendedDefaultRules扩展,这基本上就是我上面所做的,并将()推入类型变量来制作东西在互动环节中工作。