If you have f' = maybe Nothing f
, then the types have to be f :: a -> Maybe b
and f' :: Maybe a -> Maybe b
(where a
and b
may be variables or specific types), or it won't type-check. But this is just the type of >>=
for the Maybe
monad: Maybe a -> (a -> Maybe b) -> Maybe b
! So maybe Nothing f
can be written as (>>= f)
.
質問
I often have a code that has "maybe Nothing someFunc" pattern:
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"
Here parseUSDate
has type Text -> Maybe Date
.
Aeson parsing obviously returns Maybe Text
.
So it looks to me that I need to lift through 2 layers of Maybe
here. And I have no clue how to do it any other way but with maybe Nothing someFunc
pattern.
Am I missing some obvious "flatten" or whatever function that I could use here?
EDIT: Thanks for Alexey's answer.
This is exactly what i was looking for. Here's the end result:
instance FromJSON SaveSection where
parseJSON (Object o) =
SaveSection <$>
o .:? "eventId" <*>
((>>= parseUSDate) <$> o .:? "eventDate") <*>
o .:? "eventRecId" <*>
o .:? "idxId" <*>
((>>= parseUSDate) <$> o .:? "idxDate") <*>
o .:? "idxRecId"
解決 2
他のヒント
There's the ever-handy Control.Monad.join
function:
> join (Just (Just 1))
Just 1
> join (Just Nothing)
Nothing
> join Nothing
Nothing
I'm not an expert on Aeson, but if I do:
> :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)
Is that the sort of thing you're looking for?
EDIT: Fixed so that it actually works... My initial generic f :: a -> Maybe a
was messing things up.
You could make an operator to clean this up:
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"
(This should work...)