1

我经常有一个具有“也许没什么 someFunc”模式的代码:

instance FromJSON SaveSection where
  parseJSON (Object o) =
      SaveSection <$>
      o .:? "eventId" <*>
      (maybe Nothing parseUSDate <$> o .:? "eventDate") <*>
      o .:? "eventRecId" <*>
      o .:? "idxId" <*>
      (maybe Nothing parseUSDate <$> o .:? "idxDate") <*>
      o .:? "idxRecId"

这里parseUSDate有类型Text -> Maybe Date

Aeson 解析显然返回Maybe Text

所以在我看来,我需要通过Maybe这里的 2 层。而且我不知道如何以任何其他方式做到这一点,除了maybe Nothing someFunc模式。

我是否缺少一些明显的“扁平化”或我可以在这里使用的任何功能?

编辑:感谢 Alexey 的回答。

这正是我想要的。这是最终结果:

instance FromJSON SaveSection where
  parseJSON (Object o) =
      SaveSection <$>
      o .:? "eventId" <*>
      ((>>= parseUSDate) <$> o .:? "eventDate") <*>
      o .:? "eventRecId" <*>
      o .:? "idxId" <*>
      ((>>= parseUSDate) <$> o .:? "idxDate") <*>
      o .:? "idxRecId"
4

2 回答 2

10

有一个非常方便的Control.Monad.join功能:

> join (Just (Just 1))
Just 1
> join (Just Nothing)
Nothing
> join Nothing
Nothing

我不是 Aeson 方面的专家,但如果我这样做:

> :m Control.Monad Control.Applicative Data.Aeson Data.Text
> :set -XOverloadedStrings
> :set +m 
> let f :: Text -> Maybe Text
|     f = Just    -- Stand-in for parseUSDate
> :t \o -> join <$> liftM f <$> o .:? "key"
Object -> Parser (Maybe Text)
> -- Has the same type as your expression
> :t \o -> maybe Nothing f <$> o .:? "key"
Object -> Parser (Maybe Text)

那是你要找的那种东西吗?

编辑:已修复,以便它实际工作......我最初的通用f :: a -> Maybe a是把事情搞砸了。


你可以让一个操作员来清理它:

infixl 9
(>>=$) :: (Functor f, Monad m) => f (m a) -> (a -> m b) -> f (m b)
m >>=$ a = join <$> liftM a <$> m

parseJSON (Object o) =
    SaveSection
        <$> o .:? "eventId"
        <*> o .:? "eventDate" >>=$ parseUSDate
        <*> o .:? "eventRecId"
        <*> o .:? "idxId"
        <*> o .:? "idxDate" >>=$ parseUSDate
        <*> o .:? "idxRecId"

(这应该工作......)

于 2014-03-31T17:45:20.073 回答
6

如果你有f' = maybe Nothing f,那么类型必须是f :: a -> Maybe band f' :: Maybe a -> Maybe b(其中ab可能是变量或特定类型),否则它不会进行类型检查。但这只是monad>>=的类型: ! 所以可以写成。MaybeMaybe a -> (a -> Maybe b) -> Maybe bmaybe Nothing f(>>= f)

于 2014-03-31T18:19:55.723 回答