了解MonadTransformer的例子

时间:2016-06-11 08:07:03

标签: haskell monad-transformers

我正在浏览https://en.wikibooks.org/wiki/Haskell/Monad_transformers

的教程

我写下了一段代码。一个没有和其他MonadTransformer实例:

-- Simple Get Password functions. 
getPassphrase1 :: IO (Maybe String)
getPassphrase1 = do
  password <- getLine
  if isValid password
  then return $ Just password
  else return Nothing


askPassphrase1 :: IO ()
askPassphrase1 = do
  putStrLn "Enter password < 8 , alpha, number and punctuation:"
  p <- getPassphrase1
  case p of
    Nothing -> do          -- Q1. ### How to implement this with `MonadTrans` ?
      putStrLn "Invalid password. Enter again:"
      askPassphrase1
    Just password ->
      putStrLn $ "Your password is " ++ password

-- The validation test could be anything we want it to be.
isValid :: String -> Bool
isValid s = length s >= 8
            && any isAlpha s
            && any isNumber s
            && any isPunctuation s

另一个人使用我自己写的MonadT

getPassphrase2 :: MaybeT IO String
getPassphrase2 = do
  password <- lift getLine
  guard $ isValid password
  return password

askPassphrase2 :: MaybeT IO ()
askPassphrase2 = do
  lift $ putStrLn "Enter password < 8 , alpha, number and punctuation:"
  p <- getPassphrase2
  -- Q1. How to print "Invalid password" ?
  lift $ putStrLn $ "Your password is " ++ p

-- The validation test could be anything we want it to be.
isValid :: String -> Bool
isValid s = length s >= 8
            && any isAlpha s
            && any isNumber s
            && any isPunctuation s

main :: IO ()
main = do
  a <- runMaybeT askPassphrase2
  return ()

两者都有效。

但我无法理解如何在wrong password示例中添加MonadTrans支持。 ?

另外,main方法是正确的吗?还是可以用更好的方式编写?

1 个答案:

答案 0 :(得分:1)

guard不是你在MaybeT方法中想要的。要检查无效密码是否能够提供您自己的处理,您只需使用原始版本的getPassphase提升到MaybeT IO monad:

getPassphease2 = do result <- lift $ getPassphrase1
                    case result of
                        Nothing -> lift $ putStrLn "bad password"
                        Just pw -> lift $ putStrLn "your password is: " ++ pw

...说明

MaybeT IO monad用于为IO-actions提供失败失败的能力,monad会自动处理该失败。如果任何步骤失败,控制将一直返回runMaybeTrunMaybeT返回Nothing。这就像抛出异常一样。

使用MaybeT的要点是您不必显式检查步骤是否失败 - 在调用每个步骤后由MaybeT monad执行检查。这意味着你可以编写代码,假设每个前面的步骤都已成功 - 即好像你在#34;愉快的路径&#34;。这也意味着如果上一步失败,您就无法做出不同的事情。

使用MaybeT getPassphrasemain = do result <- runMaybeT askPassphrase2 case result of Just _ -> return () Nothing -> putStrLn "Some failure happened... perhaps wrong password?" 的一种可能性是:

runMaybeT

问题在于,如果Nothing返回askPassphrase,则可能意味着guard中的任何步骤都失败了,而不仅仅是getPassphrase

使用MaybeT版askPassphrase的另一种方法是runMaybeT使用askPassphrase2 = do result <- lift $ runMaybeT getPassphrase2 case result of Nothing -> lift $ putStrLn "bad password" Just pw -> lift $ putStrLn $ "Your password is " ++ pw 运行它:

runMaybeT

在这里,我们像使用try-catch块一样使用Push Notification