Ale*_*lin 6 monads parsing haskell applicative aeson
我的类型和相应的 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
Run Code Online (Sandbox Code Playgroud)
一种选择是以某种方式对 的结果进行模式匹配fmap NE.nonEmpty (o .: "responses"),但我无法弄清楚那里的模式是什么:看起来 Parser 没有任何构造函数?
本质上,你需要一个Parser [a] -> Parser NE.NonEmpty变压器,这相对简单:
-- toNonEmptyP :: Parser [a] -> Parser NE.NonEmtpy
toNonEmptyP p = fmap NE.nonEmpty p >>= maybe mzero return
Run Code Online (Sandbox Code Playgroud)
我们映射NE.nonEmpty到常规列表解析器上,它为我们提供了Parser (Maybe NE.NonEmpty). 然后我们检查Maybewithmaybe并使用mzeroif it was Nothing,或者return将解析后的值返回到解析上下文。然后你的FromJSON实例归结为
instance FromJSON GSAnswer where
parseJSON (Object o) =
GSAnswer <$> o .: "question-id"
<*> toNonEmptyP (o .: "responses")
parseJSON _ = mzero
Run Code Online (Sandbox Code Playgroud)
您可以使用fail msg而不是mzero提供自定义错误消息,因为fail :: String -> Parser a不会触底。