class 的 ghci 意外行为实例
ghci unexpected behavior instance of class
我一直在研究 Bryan O'Sullivan 和他的同事 "Real World Haskell,",并在 GHCi 7.8.3 版 [=25] 下遇到了我称之为意想不到的 'laxness' =].
我“:加载”了以下 -
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 应该告诉我放风筝,因为有 2 个 fromJValue 实例。
事实上,如果我指定
fromJValue it :: Either String Bool
我猜对了,错了。问题似乎是 doubleToJValue。消除 JSON Double 实例,并向 JValue 添加 JChar Char 构造函数,以及相应的 JSON Char 实例,我从 ghci 得到了预期的 'ambiguous' 响应。
所以我认为有一个错误。
注释?谢谢...
看看到底发生了什么:
[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,因为这些是已被发现最有用(或常见)的情况。 More info on defaulting.
这不是错误,而是 ExtendedDefaultRules
extension 的结果,它在 GHCi 提示符下默认启用,但在文件中不启用。
大约,当一个类型在其他方面不明确并且具有 class 正确形式的约束时,具有此扩展的 GHC 将尝试将其默认为适合 (), Integer, Double
.[=15 的第一个类型=]
没有ExtendedDefaultRules
扩展名,比如默认在模块文件中,默认还是可以的,但是要求更严格(至少要有一个数字class,()
未尝试过)并且仅适用于一组固定的 classes,不适用于您自己定义的任何内容。
我一直在研究 Bryan O'Sullivan 和他的同事 "Real World Haskell,",并在 GHCi 7.8.3 版 [=25] 下遇到了我称之为意想不到的 'laxness' =]. 我“:加载”了以下 -
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 应该告诉我放风筝,因为有 2 个 fromJValue 实例。 事实上,如果我指定
fromJValue it :: Either String Bool
我猜对了,错了。问题似乎是 doubleToJValue。消除 JSON Double 实例,并向 JValue 添加 JChar Char 构造函数,以及相应的 JSON Char 实例,我从 ghci 得到了预期的 'ambiguous' 响应。 所以我认为有一个错误。 注释?谢谢...
看看到底发生了什么:
[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,因为这些是已被发现最有用(或常见)的情况。 More info on defaulting.
这不是错误,而是 ExtendedDefaultRules
extension 的结果,它在 GHCi 提示符下默认启用,但在文件中不启用。
大约,当一个类型在其他方面不明确并且具有 class 正确形式的约束时,具有此扩展的 GHC 将尝试将其默认为适合 (), Integer, Double
.[=15 的第一个类型=]
没有ExtendedDefaultRules
扩展名,比如默认在模块文件中,默认还是可以的,但是要求更严格(至少要有一个数字class,()
未尝试过)并且仅适用于一组固定的 classes,不适用于您自己定义的任何内容。