How to use maybe monad inside another monad?
happstack, haskell
Solution
Ok, with your generic example I could do something with `Control¸Monad.Transformers`. This allows you to create a stack of monads. You can check it out here: http://hackage.haskell.org/package/transformers-0.3.0.0/docs/Control-Monad-Trans-Maybe.html You can apply MaybeT to everything of type `IO (Maybe a)` and then do all the computations in the inner do block and then check for Nothing at the end.
module Main where
import Control.Monad.Trans.Maybe
getAnswer expected = MaybeT $ do
l <- getLine
if l == expected
then return $ Just l
else return $ Nothing
main = do
y <- runMaybeT $ do a <- getAnswer "a"
b <- getAnswer a
return b
case y of Nothing -> putStrLn "failure"
(Just _) -> putStrLn "correct"
Another version using `liftIO` and the `Alternative` type class:
module Main where
import Control.Monad.Trans.Maybe
import Control.Monad.IO.Class
import Control.Applicative
getAnswer expected = MaybeT $ do
l <- getLine
if l == expected
then return $ Just l
else return $ Nothing
main = do
_ <- runMaybeT $ do a <- getAnswer "a"
b <- getAnswer a
liftIO $ putStrLn "correct"
<|> do liftIO $ putStrLn "failure"
return ()
But using many lift operations is not very elegant.
Problem
I have this code (inside happstack, but could be just the IO monad): ``` accountHandler conn = do sessionId <- optional $ readCookieValue "sessionId" case sessionId of Nothing -> seeOther ("/" :: String) $ toResponse () Just s -> do result <- loggedInUserId conn s case result of Just userId -> seeOther ("/account/" ++ unUserId userId) $ toResponse () Nothing -> seeOther ("/" :: String) $ toResponse () ``` I want to remove the nested case statements and write something like: ``` accountHandler conn = do let action = do sessionId <- optional $ readCookieValue "sessionId" userId <- loggedInUserId conn sessionId return $ seeOther ("/account/" ++ userId) maybe (seeOther ("/" :: String)) id action $ toResponse () ``` ... but userId ends up as a type of `Maybe String` rather than just `String`. How can I evaluate the nested `do` block using the maybe monad? (I would also accept a different refactoring that removes the nested cases.) UPDATE: Below is a generic, though contrived, version of the same problem: ``` module Main where getAnswer expected = do l <- getLine if l == expected then return $ Just l else return $ Nothing main = do a <- getAnswer "a" case a of Nothing -> putStrLn "nope" Just x -> do b <- getAnswer x case b of Nothing -> putStrLn "nope" Just _ -> putStrLn "correct!" ```