Maybe constructing data from Maybes
Before Applicative
s, you still can do
parseFoo :: String -> Maybe Foo
parseFoo line =
case (parseBar line, parseBaz line) of
(Just bar, Just baz) -> Just Foo { bar=bar baz=baz }
_ -> Nothing
and avoid defining the parseFoo'
function.
This is what the Monad
instance of Maybe
is all about. You can thus calculate your Maybe Foo
with:
parseFoo :: String -> Maybe Foo
parseFoo line = do
bar <- parseBar line
baz <- parseBaz line
parseFoo' bar baz
Here bar
and baz
are not Maybe Bar
and Maybe Baz
objects, but Bar
and Baz
objects. You thus can define a parseFoo
with:
parseFoo' :: Bar -> Baz -> Maybe Foo
parseFoo' bar baz = Just Foo { bar=bar baz=baz }
Here from the moment a computation returns a Nothing
, it means that the result is a Nothing
, so only if the parseBar line
returns a Just …
, and the parseBaz
returns a Just …
, it will thus return the result of parseFoo bar baz
.
This is because the Monad
instance of Maybe
is implemented as:
instance Monad Maybe where
return = Just
Nothing >>= _ = Nothing
Just x >>= f = f x
A do
block is syntactical sugar, so the above do
block is converted to:
parseFoo line = parseBar line >>= \bar -> (parseBaz line >>= \baz -> parseFoo bar baz)
If parseFoo
always returns Just
in case it retrieves two Just
s, we can implement this as:
parseFoo' :: Bar -> Baz -> Foo
parseFoo' bar baz = Foo { bar=bar baz=baz }
In that case we can make ues of (<$>) :: Functor f => (a -> b) -> f a -> f b
and (<*>) :: Applicative f => f (a -> b) -> f a -> f b
to process the data:
parseFoo :: String -> Maybe Foo
parseFoo line = parseFoo' <$> parseBar line <*> parseBaz line
In this specific case, parseFoo
is however semantically the same as Foo
, so we do not need a parseFoo
, and can work with:
parseFoo :: String -> Maybe Foo
parseFoo line = Foo <$> parseBar line <*> parseBaz line
Luckily you don't need the full power of monads for this. Applicative functors are all you need:
parseFoo line = Foo <$> parseBar line <*> parseBaz line