在进行Web编程时,很多事情发生在我身上:我想运行一个可能会失败的操作。发生故障时,我想向客户端发送500。但是,通常情况下,我只想继续执行一系列步骤。
doSomeWebStuff :: SomeWebMonad ()
doSomeWebStuff = do
res <- databaseCall
case res of
Left err -> status 500
Right val -> do
res2 <- anotherDatabaseCall (someprop val)
case res2 of
Left err -> status 500
Right val2 -> text $ show val2
由于错误是异常(exception),因此我不希望我需要所有这些案例内容来捕获它们。每当剩下的东西我都想做同样的事情。有没有一种方法可以像
guard
这样在一行上表达它,但是可以控制它在退出时返回什么?用另一种语言,我可以这样做:
function doSomeWebStuff() {
var res = databaseCall()
if (res == Error) return status 500
var res2 = anotherDatabaseCall(res.someprop)
if (res2 == Error) return status 500
return text(res2)
}
因此,我可以编写一些样板文件,但我不想让错误弄乱我的嵌套,而在这种情况下,只想继续处理发现的情况就更常见了。
什么是最干净的方法?从理论上讲,我知道我可以使用monad在失败时提前退出,但是我只看到了带有
Maybe
的示例,它会在最后返回Nothing
,而不是让我指定它返回的内容。 最佳答案
这是我要使用ErrorT
进行的操作。免责声明:我以前从未实际使用过ErrorT
。
webStuffOr500 :: ErrorT String SomeWebMonad () -> SomeWebMonad ()
webStuffOr500 action = do
res <- runErrorT action
case res of
Left err -> do
logError err -- you probably want to know what went wrong
status 500
Right () -> return ()
doSomeWebStuff :: SomeWebMonad ()
doSomeWebStuff = webStuffOr500 doSomeWebStuff'
doSomeWebStuff' :: ErrorT String SomeWebMonad ()
doSomeWebStuff' = do
val <- ErrorT databaseCall
val2 <- ErrorT $ anotherDatabaseCall (someprop val)
lift $ text $ show val2
这是我用来确保所有类型检查均正确的导入和类型声明:
import Control.Monad.Identity
import Control.Monad.Error
import Control.Monad.Trans (lift)
import Control.Monad
type SomeWebMonad = Identity
data Foo = Foo
data Bar = Bar
data Baz = Baz deriving (Show)
someprop :: Foo -> Bar
someprop = undefined
databaseCall :: SomeWebMonad (Either String Foo)
databaseCall = undefined
anotherDatabaseCall :: Bar -> SomeWebMonad (Either String Baz)
anotherDatabaseCall = undefined
logError :: String -> SomeWebMonad ()
logError = undefined
text :: String -> SomeWebMonad ()
text = undefined
status :: Int -> SomeWebMonad ()
status = undefined
如果我做错了,那么请大声喊叫。如果采用这种方法,将
databaseCall
和anotherDatabaseCall
的类型签名修改为也使用ErrorT
可能是明智的,这样就可以将a <- ErrorT b
简化为a <- b
中的doSomeWebStuff'
。由于我是
ErrorT
的完全菜鸟,所以除了“这里有一些代码,去找点乐子”之外,我真的无法做任何事情。关于haskell - 如何在Web Monad中 “escape early”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9034176/