我的类型和相应的FromJSON实现,如下所示。
nonEmpty
将List
变为Maybe NonEmpty
,我正在尝试正确处理List
确实为空的情况,我必须中止解析。这个解析实际上是在parseJsonBody
内部完成的,这意味着我不希望error "foo"
以我的方式离开它,但我想返回mzero
(或其他任何可以做的伎俩,mzero
是我到目前为止唯一偶然发现的事情),以便处理程序正确返回400而不是使用500崩溃。
下面的方法编译,但据我所知,它几乎等于error
或在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
一种选择是以某种方式对fmap NE.nonEmpty (o .: "responses")
的结果进行模式匹配,但我无法弄清楚模式会是什么:看起来Parser看起来有没有任何构造函数?
答案 0 :(得分:3)
基本上,你需要一个Parser [a] -> Parser NE.NonEmpty
变换器,这相对容易:
-- toNonEmptyP :: Parser [a] -> Parser NE.NonEmtpy
toNonEmptyP p = fmap NE.nonEmpty p >>= maybe mzero return
我们在常规列表解析器上映射NE.nonEmpty
,这会给我们Parser (Maybe NE.NonEmpty)
。然后,我们使用Maybe
检查maybe
,如果是mzero
则使用Nothing
,或者将解析后的值return
返回到解析上下文。您的FromJSON
实例然后归结为
instance FromJSON GSAnswer where
parseJSON (Object o) =
GSAnswer <$> o .: "question-id"
<*> toNonEmptyP (o .: "responses")
parseJSON _ = mzero
您可以使用fail msg
代替mzero
来提供自定义错误消息,因为fail :: String -> Parser a
没有触底。