Parsing 如何使用Data.Aeson在JSON解析中正确地出错

Parsing 如何使用Data.Aeson在JSON解析中正确地出错,parsing,haskell,monads,applicative,aeson,Parsing,Haskell,Monads,Applicative,Aeson,我的类型和对应的JSON实现如下所示 非空将列表转换为可能非空,我正试图正确处理列表确实为空的情况,我必须中止解析。这个解析实际上是在的内部完成的,这意味着我不想通过错误“foo”来摆脱它,但我想返回mzero(或者其他任何方法,到目前为止,mzero是我唯一碰到的东西),以便处理程序正确地返回400而不是500 下面的方法可以编译,但据我所知,它相当于parseJSON内部的错误或某种其他形式的异常抛出。但是,如果我返回mzero(例如,使用mzero而不是该行),它会按照预期很好地失败 im

我的类型和对应的JSON实现如下所示

非空
列表
转换为
可能非空
,我正试图正确处理
列表
确实为空的情况,我必须中止解析。这个解析实际上是在的内部完成的,这意味着我不想通过
错误“foo”
来摆脱它,但我想返回
mzero
(或者其他任何方法,到目前为止,
mzero
是我唯一碰到的东西),以便处理程序正确地返回400而不是500

下面的方法可以编译,但据我所知,它相当于parseJSON内部的
错误
或某种其他形式的异常抛出。但是,如果我返回
mzero
(例如,使用
mzero
而不是该行),它会按照预期很好地失败

import qualified Data.List.NonEmpty as NE
data GSAnswer = GSAnswer { gsAnswerQuestionId :: Int
                         , gsAnswerResponses :: NE.NonEmpty GSResponse
                         } deriving (Show, Eq)


instance FromJSON GSAnswer where
  parseJSON (Object o) =
    GSAnswer <$> o .: "question-id"
             -- how do I return mzero here based on NE.nonEmpty?
             -- this will throw an exception right now on an empty list
             <*> fmap (fromMaybe (fail "foo") . NE.nonEmpty) (o .: "responses")
  parseJSON _ = mzero
导入符合条件的Data.List.NonEmpty作为NE
数据GSAnswer=GSAnswer{gsAnswerQuestionId::Int
,gsanswerresponse::NE.NonEmpty GSResponse
}推导(显示,等式)
实例FromJSON GSAnswer where
parseJSON(对象o)=
GSO回答:“问题id”
--如何基于NE.nonEmpty在这里返回mzero?
--这将立即在空列表上引发异常
fmap(fromaybe(fail“foo”).NE.非空)(o.:“回复”)
parseJSON=mzero

一种选择是在
fmap NE.nonEmpty(o.:“responses”)
的结果上以某种方式进行模式匹配,但我不太清楚模式会是什么:解析器看起来没有任何构造函数?

本质上,您需要一个
解析器[a]->Parser NE.nonEmpty
转换器,这相对简单:

-- toNonEmptyP :: Parser [a] -> Parser NE.NonEmtpy
toNonEmptyP p = fmap NE.nonEmpty p >>= maybe mzero return
我们在常规的列表解析器上映射
NE.nonEmpty
,这给了我们
解析器(可能是NE.nonEmpty)
。然后,我们使用
Maybe
检查
Maybe
,如果
,则使用
mzero
,或者
将解析后的值返回到解析上下文。您的
FromJSON
实例可以归结为

instance FromJSON GSAnswer where
  parseJSON (Object o) =
    GSAnswer <$> o .: "question-id"
             <*> toNonEmptyP (o .: "responses")
  parseJSON _ = mzero
json GSAnswer中的实例
parseJSON(对象o)=
GSO回答:“问题id”
toNonEmptyP(o.:“回复”)
parseJSON=mzero

您可以使用
fail-msg
而不是
mzero
来提供自定义错误消息,因为
fail::String->Parser a
并没有见底。

似乎可以做到这一点,谢谢。关于如何将特定错误消息添加到解析器失败,有什么建议吗?现在报告的错误消息是“mzero”,如果我可以在那里传递我自己的错误消息,解释为什么解析器必须中止,那就太好了。您是否在转换器中尝试了
fail“msg”
而不是
mzero
?我目前不在我的电脑上,但我可以稍后检查。这似乎可以解决问题,谢谢,我将上面的更改为:toNonEmptyP::String->Parser[a]->Parser(NE.NonEmpty a)toNonEmptyP msg p=fmap NE.NonEmpty p>>=maybe(fail msg)return