2

可以说我有以下结构:

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在这种情况下我仍然不知道如何使用和使用模式匹配:(

4

2 回答 2

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!!!"
于 2015-10-27T19:42:27.990 回答
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 _ =...答案以完成此答案,否则编译器会警告我的函数的可反驳性。

于 2015-10-27T19:00:48.277 回答