Haskell中的JSON解析:格式错误的值失败

时间:2015-07-18 17:18:14

标签: json parsing haskell

我有一个我想从JSON解析的记录:

data ArticleInfo = ArticleInfo {
    author :: String,
    title :: String,
    pubDate :: Day
} deriving (Show, Eq)

instance FromJSON ArticleInfo where
    parseJSON (Object value) = ArticleInfo <$>
        value .: "author" <*>
        value .: "title" <*>
        liftM parsePubDate (value .: "pubDate")
    parseJSON _ = mzero

parsePubDate :: String -> Day
parsePubDate = parseTimeOrError True defaultTimeLocale "%Y-%-m-%-d"

parseArticleInfo :: String -> Maybe ArticleInfo
parseArticleInfo source = Data.Yaml.decode (pack source)

这样可行,但在不符合"%Y-%-m-%-d"格式说明符的格式不正确的日期崩溃。解析器规范目前在我头顶 - 当我遇到这样的日期时,我在那里写什么来使ArticleInfo解析器返回Nothing

(我知道我应该首先将parseTimeOrError替换为parseTime,但这就是它。甚至parseTime也被弃用,告诉我使用parseTimeM签名我还不明白。)

2 个答案:

答案 0 :(得分:2)

这是Maybe monad的典型用法。对于初学者来说,这并不是那么明显,但是一旦你了解monad就会成为第二天性。

parsePubDate :: String -> Maybe Day
parsePubDate = parseTimeM True defaultTimeLocale "%Y-%-m-%-d"

答案 1 :(得分:2)

如果你没有使整个解析器失败,如果有一个无效的日期,你可以在没有太多麻烦的情况下解决它:

parseJSON (Object value) = ArticleInfo <$>
    value .: "author" <*>
    value .: "title" <*>
    (value .: "pubDate" >>= parseTimeM True defaultTimeLocale "%Y-%-m-%-d")

相反,如果您需要Maybe ArticleInfo的解析器(我最初想到的,但现在意识到您可能不想要),请继续阅读...

首先,如果您要解析Maybe ArticleInfo,您的FromJSON实例将需要Maybe ArticleInfo,而不是ArticleInfo。 (这样做需要语言扩展名FlexibleInstances。)其次,您还需要更改parsePubDate以返回Maybe Day,并将parseTimeOrError替换为{ {1}}。 (事实上​​,当parseTimeM专注于parseTimeM时,m ~ Monad的功能与弃用的parseTimeM相同。)

然后事情变得复杂一些。有点冗长,你可以这样做:

parseTime

...但这有点重复,并不是一个非常“好”的解决方案。您也可以使用MaybeT monad变换器,这可能会更好一些:

parseJSON (Object value) = (\a t pd -> ArticleInfo a t <$> pd) <$>
    value .: "author" <*>
    value .: "title" <*>
    liftM parsePubDate (value .: "pubDate")

此外,所有这些都使parseJSON (Object value) = runMaybeT $ ArticleInfo <$> lift (value .: "author") <*> lift (value .: "title") <*> (MaybeT $ parsePubDate <$> value .: "pubDate") 返回Data.Yaml.decode (pack source)。您可以使用Maybe (Maybe ArticleInfo)join折叠起来。