gpt4 book ai didi

haskell - 如何在网络单子(monad)中 "escape early"

转载 作者:行者123 更新时间:2023-12-03 14:52:39 26 4
gpt4 key购买 nike

在 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 <- bdoSomeWebStuff' .

因为我是 ErrorT 的菜鸟,除了“这里有一些代码,去玩玩”之外,我真的不能做任何手 Handlebars 。

关于haskell - 如何在网络单子(monad)中 "escape early",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9034176/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com