因为我之前在其他问题上过于简单,所以我想在这里给出一个更清晰的例子.
如何在不嵌套多个案例的情况下处理必须以顺序方式检查certian条件的情况?使用"顺序方式"我的意思是获取一个值(例如来自stdin),检查该值是否适用于某个条件,并取决于获得另一个值的结果等等.
例:
sequen :: IO String
sequen = do
a <- getLine
case a of
"hi" -> do
putStrLn "hello!"
b <- getLine
case b of
"how are you?" -> do
putStrLn "fine, thanks"
return "nice conversation"
_ -> return "error 2"
_ -> return "error 1"
Run Code Online (Sandbox Code Playgroud)
我知道有更好的方法来编写这样的聊天机器人,它应该只是展示问题的顺序性.正如您所看到的,对于每个嵌套的情况,代码也会缩进.
有没有办法更好地构建这样的代码?我正在考虑在一个地方处理"错误"并描述"成功路径"而不分配错误处理.
Gab*_*lez 21
当然.这正是EitherT为此而制造的.你可以从它Control.Monad.Trans.Either的eitherT包装.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Either
main = do
e <- runEitherT $ do
a <- lift getLine
case a of
"hi" -> lift $ putStrLn "hello!"
_ -> left 1
b <- lift getLine
case b of
"how are you?" -> lift $ putStrLn "fine, thanks!"
_ -> left 2
return "nice conversation"
case e of
Left n -> putStrLn $ "Error - Code: " ++ show n
Right str -> putStrLn $ "Success - String: " ++ str
Run Code Online (Sandbox Code Playgroud)
EitherT每当遇到left语句时就中止当前代码块,人们通常使用它来指示错误条件.
内部块的类型是EitherT Int IO String.当你runEitherT这样,你得到IO (Either Int String).所述Left类型对应于在那里它没有用的情况left和Right值意味着它成功地到达该块的末端.
我一段时间地写了一系列帖子,回顾了我自己对Either&EitherT类型的学习.你可以在这里阅读:http://watchchrislearn.com/blog/2013/12/01/working-entirely-in-eithert/
我使用该errors软件包来获得一堆使用EitherT的好帮手(例如left,right函数返回提升版本的Left和Right).
通过将潜在的失败条件提取到自己的帮助程序中,可以使代码的主线完全按顺序读取,而不会检查结果的case语句.
从那篇文章中,你可以看到该runEitherT部分是一个连续的工作块,它恰好具有失败机制EitherT.显然,这段代码是相当专业的,以显示MaybeT内部的播放方式EitherT.在真实的代码中,它只是你想要讲述的故事,只有一个Left/ Right最后.
import Control.Error
import Control.Monad.Trans
-- A type for my example functions to pass or fail on.
data Flag = Pass | Error
main :: IO ()
main = do
putStrLn "Starting to do work:"
result <- runEitherT $ do
lift $ putStrLn "Give me the first input please:"
initialText <- lift getLine
x <- eitherFailure Error initialText
lift $ putStrLn "Give me the second input please:"
secondText <- lift getLine
y <- eitherFailure Pass (secondText ++ x)
noteT ("Failed the Maybe: " ++ y) $ maybeFailure Pass y
case result of
Left val -> putStrLn $ "Work Result: Failed\n " ++ val
Right val -> putStrLn $ "Work Result: Passed\n " ++ val
putStrLn "Ok, finished. Have a nice day"
eitherFailure :: Monad m => Flag -> String -> EitherT String m String
eitherFailure Pass val = right $ "-> Passed " ++ val
eitherFailure Error val = left $ "-> Failed " ++ val
maybeFailure :: Monad m => Flag -> String -> MaybeT m String
maybeFailure Pass val = just $ "-> Passed maybe " ++ val
maybeFailure Error _ = nothing
Run Code Online (Sandbox Code Playgroud)