假设我有以下结构:
import Data.JSON
import Data.List
data Lang = Lang { name :: String,
desc :: String }
derive Show Lang
instance ToJSON Lang where
toJSON Lang{name, desc} =
Struct [
assoc "name" name,
assoc "desc" desc
]
到目前为止,我可以将Lang实例转换为JSON:
langEn = Lang { name = "en",
desc = "english" }
langEnJSON = toJSON langEn --- produces {"name" : "en", "desc" : "english"}
但我无法弄清楚如何实施相反的操作:
instance FromJSON Lang where
fromJSON (Struct fields) = ---
我首先阅读了文档,但我担心在这种情况下仍然无法使用fromJSON
并使用模式匹配:(
答案 0 :(得分:1)
最后我提出了这个解决方案:
instance FromJSON Lang where
fromJSON (Struct fields)
| Just name <- lookup "name" fields
= case lookup "desc" fields of
Just pdesc -> do
fname <- fromJSON name
fdesc <- fromJSON pdesc
return Lang { name = fname, desc = fdesc }
Nothing -> do
return Lang { name = "", desc = "" }
| otherwise = fail "error"
fromJSON _ = fail "error" --- Updated 28/10/2015
现在我可以解析传入的字符串,如:
--- returns "english"
case (parseJSON "{\"name\":\"en\",\"desc\":\"english\"}") of
Just Lang {name,desc} -> name
_ -> ""
2015年10月28日更新
就像评论中提到的Ingo一样。我应该添加fromJSON _ =...
答案以完成这个答案,否则编译器会警告我的函数的可反复性。
答案 1 :(得分:1)
以下内容应该有效:
instance FromJSON Lang where
fromJSON v = case v of
Struct s → do
name ← field "name" s
desc ← field "desc" s
return Lang{name, desc}
_ → fail ("expected {\"name\" : ..., \"desc\" : ...}, found " ++ show v)
请注意,这允许一些输入,如:
{"name" : "pl", "desc" : "polskij", "script" : "latin"}
如果你想变得迂腐,你也可以更明确地匹配Struct
之后的关联列表:
fromJSON (Struct s) = case sort s of
[("desc", desc), ("name", name)] -> do
sname <- fromJSON name
sdesc <- fromJSON desc
return Lang{name=sname, desc=sdesc}
_ -> fail "extra or missing fields"
fromJSON _ = fail "I want a struct!!!"