展平Maybes

时间:2014-03-31 17:31:55

标签: haskell maybe

我经常有一个“也许没有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

所以在我看来,我需要在这里提升2层Maybe。我不知道如何以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"

2 个答案:

答案 0 :(得分: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"

(这应该有用......)

答案 1 :(得分:6)

如果您有f' = maybe Nothing f,则类型必须为f :: a -> Maybe bf' :: Maybe a -> Maybe b(其中ab可能是变量或特定类型),或者它不会进行类型检查。但这只是Maybe monad的>>=类型:Maybe a -> (a -> Maybe b) -> Maybe b!因此maybe Nothing f可以写成(>>= f)