1

我需要将类型的值转换为Distribution.PackageDescription.FlagName带有包的 JSONText.JSON对象json
我最终采用了以下方法:

instance JSON FlagName where
    showJSON (FlagName n) = makeObj [ ("FlagName", showJSON n) ]
    readJSON object = do
        obj <- readJSON object
        flag <- valFromObj "FlagName" obj
        return flag

当我尝试对一个值进行编码并再次对其进行解码时,会发生以下情况:

> showJSON (FlagName "foo")  
JSObject (JSONObject {fromJSObject = [("FlagName",JSString (JSONString {fromJSString = "foo"}))]})  
> readJSON (showJSON (FlagName "foo")) :: Result FlagName  
Error "Unable to read JSObject"

我猜错误就在那一行:obj <- readJSON object
如何强制 Haskell 使用实例中的readJSON函数?JSON String

更新:我现在发现了一个相当老套的解决方案:

instance JSON FlagName where
    showJSON (FlagName n) = makeObj [ ("FlagName", showJSON n) ]

    readJSON object = do
        obj <- readJSON (showJSON (FlagName "foo")) :: Result (JSObject JSValue)
        let maybeFlagName = lookup "FlagName" $ fromJSObject obj
        maybe (fail "Not a FlagName object") (\jsn -> liftM FlagName $ (readJSON jsn :: Result String)) maybeFlagName

如果有人提出更优雅的解决方案,我将不胜感激......

4

2 回答 2

2

好的,我自己找到了答案:
valFromObj返回FlagName(即 a String)的名称而不是FlagName本身。

instance JSON FlagName where
    showJSON (FlagName n) = makeObj [ ("FlagName", showJSON n) ]
    readJSON object = do
        obj <- readJSON object
        n <- valFromObj "FlagName" obj
        return $ FlagName n
于 2012-09-05T21:05:18.347 回答
1

最好进行模式匹配,这样您就可以处理 object 不是 of 的情况JSObject。除了失败,你还可以做一些其他的事情。您将需要import Control.Applicative使用<$>. 我只是更喜欢这些事情的应用语法。

 instance JSON FlagName where
     showJSON (FlagName n) = makeObj [ ("FlagName", showJSON n) ]
     readJSON (JSObject obj) = FlagName <$> valFromObj "FlagName" obj
     readJSON _ = fail "unknown object"
于 2012-09-06T04:28:28.457 回答