Search code examples
haskellmonadsdo-notation

How to use Do notation with both Maybe and IO


I am trying to get a good grip on the do notation in Haskell.

I could use it with Maybe and then print the result. Like this:

maybeAdd :: Maybe Integer
maybeAdd = do one <- maybe1
              two <- maybe2
              three <- maybe3
              return (one + two + three)

main :: IO ()
main = putStr (show $ fromMaybe 0 maybeAdd)

But instead of having a separate function I am trying to use the do notation with the Maybe inside the main function. But I am not having any luck. The various attempts I tried include:

main :: IO ()
main = do one <- maybe1
          two <- maybe2
          three <- maybe3
          putStr (show $ fromMaybe 0 $ return (one + two + three))
main :: IO ()
main = do one <- maybe1
          two <- maybe2
          three <- maybe3
          putStr (show $ fromMaybe 0 $ Just (one + two + three))
main :: IO ()
main = do one <- maybe1
          two <- maybe2
          three <- maybe3
          putStr (show $ (one + two + three))

All of these leads to various types of compilation errors, which unfortunately I failed to decipher to get the correct way to do it.

How do I achieve the above? And perhaps maybe an explanation of why the approaches I tried were wrong also?


Solution

  • Each do block must work within a single monad. If you want to use multiple monads, you could use multiple do blocks. Trying to adapt your code:

    main :: IO ()
    main = do -- IO block
       let x = do -- Maybe block
              one <- maybe1
              two <- maybe2
              three <- maybe3
              return (one + two + three)
       putStr (show $ fromMaybe 0 x)
    

    You could even use

    main = do -- IO block
       putStr $ show $ fromMaybe 0 $ do -- Maybe block
          one <- maybe1
          two <- maybe2
          three <- maybe3
          return (one + two + three)
       -- other IO actions here
    

    but it could be less readable in certain cases.