1

我不确定我是否在这里找错了树,但我有一个 AesonFromJSON定义,看起来相当庞大,我想知道它是否可以变成更简洁的东西。如果 URI 的嵌套解析失败,我想缩短整个对象的解析。

data Link = Link { link :: URI
                 , tags :: [String]
                 } deriving (Show, Typeable, Eq)

instance FromJSON Link where
    parseJSON :: Value -> Parser Link
    parseJSON (Object o) = do
        linkStr <- o .: "link"
        tags' <- o .: "tags"

        case parseURI linkStr of
            Just l -> return $ Link l tags'
            Nothing -> mzero

    parseJSON _ = mzero

parseURIisparseURI :: String -> Maybe URI和 both的类型Maybe以及Parser具有MonadPlus实例。有没有办法将两者直接组合并在最后删除丑陋的case语句?

4

2 回答 2

4

应用解析器通常更简洁,您可以组合parseURI使用maybe mzero returnwhich 将 aNothing转换为mzero.

instance FromJSON Link where
    parseJSON :: Value -> Parser Link
    parseJSON (Object o) = Link
        <$> (maybe mzero return . parseURI =<< o .: "link")
        <*> o .: "tags"

    parseJSON _ = mzero
于 2015-03-19T21:38:01.363 回答
1

模式匹配有效,但这仅适用于do不明确的符号内部>>=,因为会进行额外的脱糖:

instance FromJSON Link where
    parseJSON (Object o) = do
        Just link' <- o .: "link"
        tags'      <- o .: "tags"
        return $ Link link' tags'
    parseJSON _ = mzero

> -- Note that I used link :: String for my testing instead
> decode "{\"link\": \"test\", \"tags\": []}" :: Maybe Link
Just (Link {link = "test", tags=[]})
> decode "{\"tags\": []}" :: Maybe Link
Nothing

这里发生的是 a 左侧失败的模式匹配<-正在调用fail. 查看 for 的来源告诉Parser我,它fail正在调用failDesc,它也被 的实现使用mzero,所以在这种情况下你是安全的。一般来说,它只是调用fail,它可以根据 monad 做任何事情,但Parser我认为这是有道理的。

但是,@shang 的答案肯定更好,因为它不依赖于隐式行为。

于 2015-03-19T21:55:40.433 回答