7

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

nonEmptyaList变为 a 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 没有任何构造函数吗?

4

1 回答 1

4

本质上,您需要一个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). 然后我们检查Maybewithmaybe并使用mzeroif it is 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不会触底。

于 2015-02-13T07:21:37.803 回答