如何在另一个monad中使用monad?

Xav*_*hay 7 haskell happstack

我有这个代码(在happstack里面,但可能只是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 ()
Run Code Online (Sandbox Code Playgroud)

我想删除嵌套的case语句并写下如下内容:

accountHandler conn = do

  let action = do
                sessionId <- optional $ readCookieValue "sessionId"
                userId    <- loggedInUserId conn sessionId

                return $ seeOther ("/account/" ++ userId)

  maybe (seeOther ("/" :: String)) id action $ toResponse ()
Run Code Online (Sandbox Code Playgroud)

...但是userId最终Maybe String只是一种而不仅仅是String.如何do使用monad来评估嵌套块?(我也会接受一个不同的重构来删除嵌套的案例.)

更新:以下是同一问题的通用但经过设计的版本:

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!"
Run Code Online (Sandbox Code Playgroud)

MoF*_*oFu 5

好的,通过你的通用例子,我可以做些什么Control¸Monad.Transformers.这允许您创建一组monad.你可以在这里查看:http: //hackage.haskell.org/package/transformers-0.3.0.0/docs/Control-Monad-Trans-Maybe.html你可以将MaybeT应用于所有类型IO (Maybe a) ,然后进行所有计算在内部do块中,然后在最后检查Nothing.

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"
Run Code Online (Sandbox Code Playgroud)

使用的另一个版本liftIOAlternative类型类:

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 ()
Run Code Online (Sandbox Code Playgroud)

但是使用许多升降机操作并不是很优雅.