2

我一直在浏览 Bryan O'Sullivan 和他的同事的“Real World Haskell”,并在 Windows 下遇到了我称之为 GHCi 版本 7.8.3 的意外“松懈”。我“:加载”以下 -

module JSONModule   where

data JValue = JNumber Double
           | JBool Bool
             deriving ( Show, Eq, Ord )


class JSON a where
  toJValue :: a -> JValue
  fromJValue :: JValue -> Either String  a


fromJBool (JBool b) = Right b
fromJBool _ = Left "not a JSON boolean"

instance JSON Double where
  toJValue = JNumber
  fromJValue = doubleToJValue id

instance JSON Bool where
  toJValue = JBool
  fromJValue = fromJBool

doubleToJValue :: (Double -> a) -> JValue -> Either String a
doubleToJValue f (JNumber v) = Right (f v)
doubleToJValue _ _ = Left "not a JSON number"

然后,在 ghci 中:

*JSONModule> :r
[1 of 1] Compiling JSONModule       ( JSONModule.hs, interpreted )
Ok, modules loaded: JSONModule.
*JSONModule> toJValue False
JBool False
*JSONModule> fromJValue it
Left "not a JSON number"

虽然这是真的,但这不是我们所期望的。我认为 ghci 应该告诉我放风筝,因为 fromJValue 有 2 个实例。确实,如果我指定

fromJValue it :: Either String Bool

我得到正确的错误。问题似乎是 doubleToJValue。消除 JSON Double 实例,并将 JChar Char 构造函数添加到 JValue 和 JSON Char 的相应实例,我从 ghci 得到预期的“模糊”响应。所以我认为有一个错误。注释?谢谢...

4

2 回答 2

4

这不是错误,而是ExtendedDefaultRules扩展名的结果,默认情况下在 GHCi 提示符下启用,但不在文件中。

大约,当一个类型在其他方面不明确并且具有正确形式的类约束时,具有此扩展名的 GHC 将尝试将其默认为适合(), Integer, Double.

没有ExtendedDefaultRules扩展名,例如在默认情况下在模块文件中,仍然可能发生默认情况,但要求更严格(至少必须涉及一个数字类,并且()未尝试)并且仅适用于一组固定的类,而不适用任何你自己定义的。

于 2015-03-06T05:54:23.637 回答
3

看看到底发生了什么:

[1 of 1] Compiling JSONModule       ( test.hs, interpreted )
Ok, modules loaded: JSONModule.
>:set -Wall
>:t fromJValue (toJValue False)
fromJValue (toJValue False) :: JSON a => Either String a
> fromJValue (toJValue False)

<interactive>:6:2: Warning:
    Defaulting the following constraint(s) to type `Double'
      (JSON a0) arising from a use of `it' at <interactive>:6:2-28
      (Show a0) arising from a use of `print' at <interactive>:6:2-28
    In the first argument of `print', namely `it'
    In a stmt of an interactive GHCi command: print it
Left "not a JSON number"

如您所见,ghc 将模糊类型变量默认为 Double。当没有 Double 的实例时它给出模棱两可的类型错误的原因是因为默认行为是仅对 Integer 或 Double 的默认约束,因为这些情况已被发现是最有用的(或常见的)。有关违约的更多信息。

于 2015-03-06T05:45:59.433 回答