【发布时间】:2014-09-11 01:24:51
【问题描述】:
此代码将递归 JSON 结构解析为我制作的 haskell 对象。我正在使用 Aeson 库。我遇到的问题是我希望能够轻松地进行错误检查,即使使用递归调用也是如此。现在,每当发生错误时,我都会使用一个虚拟值 (ayyLmao)。但是,我想利用从 Parser monad 获得的错误检查。我该如何做到这一点并可能在此过程中清理我的代码?如有必要,我还可以发布一些示例 JSON。
编辑:我想指出我想摆脱“ayyLmao”(因此是愚蠢的名字),并以某种方式使用 Parser monad 的“mzero”来代替我的错误检查。
type Comments = Vector Comment
data Comment = Comment
{ author :: Text
, body :: Text
, replies :: Comments
} deriving Show
-- empty placeholder value (only should appear when errors occur)
ayyLmao :: Comment
ayyLmao = Comment "Ayy" "Lmao" V.empty
parseComment :: Object -> Maybe Comments
parseComment obj = flip parseMaybe obj $ \listing -> do
-- go through intermediate objects
comments <- listing .: "data" >>= (.: "children")
-- parse every comment in an array
return $ flip fmap comments $ \commentData -> case commentData of
-- if the data in the array is an object, parse the comment
-- (using a dummy value on error)
Object v -> fromMaybe ayyLmao (parseMaybe parseComment' v)
-- use a dummy value for errors (we should only get objects in
-- the array
_ -> ayyLmao
where
parseComment' :: Object -> Parser Comment
parseComment' v = do
-- get all data from the object
comment <- v .: "data"
authorField <- comment .: "author"
bodyField <- comment .: "body"
replyObjs <- comment .: "replies"
return $ case replyObjs of
-- if there are more objects, then parse recursively
Object more -> case parseComment more of
-- errors use the dummy value again
Just childReplies -> Comment authorField bodyField childReplies
Nothing -> ayyLmao
-- otherwise, we've reached the last comment in the
-- tree
_ -> Comment authorField bodyField V.empty
编辑:下面答案中的代码是正确的,但我想添加我修改后的解决方案。给出的解决方案假定“null”表示不再有回复,但出于某种原因,API 设计者决定应该用空字符串表示。
instance FromJSON Comment where
parseJSON = withObject "Comment" $ \obj -> do
dat <- obj .: "data"
commReplies <- dat .: "replies"
Comment
<$> dat .: "author"
<*> dat .: "body"
<*> case commReplies of
Object _ -> getComments <$> dat .: "replies"
String "" -> return V.empty
_ -> fail "Expected more comments or a the empty string"
【问题讨论】:
-
使用占位符值不是非常惯用的 Haskell,您是否考虑过返回一个
Maybe Comments值来表示失败的概念,然后在您可能会使用Data.Maybe.fromMaybe (ayyLmao)得到Nothing时反而?或者,您可以利用 Aeson 解析器具有失败概念的事实,并以几乎相同的方式使用它。 -
@bheklilr 是的,使用占位符值不是很惯用的任何东西,这就是为什么我给它起了这么愚蠢的名字。使用 Maybe 会起作用,但我更愿意只使用 Aeson 已经拥有的错误检查(Parser 的 mzero 将被解释为错误)。但是,我不太清楚如何让类型按照我想要的方式排列。这样做有什么技巧吗?
-
嗯,通常解析类型使用
mzero来表示失败。你看过this one这样的教程吗? -
是的,我知道。从我的回复中:“解析器的 mzero 将被解释为错误”。我想知道在这种情况下我该怎么做。我正在处理 cmets 向量,所以我基本上必须识别 fmap 中间的错误,并以某种方式返回整个事情的 mzero。或者我可以有一个解析器列表,然后将它折叠到一个更大的解析器中(这甚至可以工作吗?)。不完全确定在那里做的最好的事情是什么。