Search code examples
haskellmonadsfunctoroption-type

Haskell avoiding double-wrapped maybes in functions that return maybes


I can see that there's a lot of questions asking about the Maybe type and composition here, but I'm quite stuck and reading these has my head hurting, if I'm being quite honest.

Here's my situation:

Say, for the sake of example, I have a function:

addm a b = Just (a + b)

How can I create a function add :: Maybe Int -> Maybe Int -> Maybe Int using the addm function without using pattern matching to unwrap the Maybes?

I have tried something like

add x y = (addm <$> x) <*> y

but this has a type of Maybe Int -> Maybe Int -> Maybe (Maybe Int)

I'd also like to avoid using anything outside of the standard library if possible.

Edit: In my specific case, I actually only needed a function Maybe Int -> Int -> Maybe Int so I was able to use

add x y = x >>= addm y

which did the trick. I'm stil curious about the answer to the original question, though.


Solution

  • There are a number of ways to write this. All involve the fact that Maybe is a Monad.

    Perhaps the easiest way to understand is to use the join function, which, for any Monad, removes the outermost level of nesting. Here it has type Maybe (Maybe a) -> Maybe a, which is exactly what you are looking for, in combination with standard Applicative operators:

    add ma mb = join $ addm <$> ma <*> mb
    

    Or you can use do notation to write the computation in a more imperative style, with what look like variable assignments, in which the Monad takes care of propagating any Nothing values:

    add ma mb = do
        a <- ma
        b <- mb
        addm a b
    

    Or you could explicitly use the "bind" (>>=) operator, which is what the do block above desugars to (but I find this less explicit and understandable than the other two options):

    add ma mb = ma >>= \a -> mb >>= \b -> addm a b