- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
无论好坏,Haskell 的流行 Servant库使得在涉及 ExceptT err IO
的 monad 转换器堆栈中运行代码变得很常见。 Servant 自己的处理程序 monad 是 ExceptT ServantErr IO
。正如许多人所说,这有点 troublesome monad因为有多种方式导致无法展开:1) 通过来自底层 IO
的正常异常,或 2) 通过返回 Left
.
如 Ed Kmett 的 exceptions
图书馆helpfully clarifies :
Continuation-based monads, and stacks such as
ErrorT e IO
which provide for multiple failure modes, are invalid instances of this [MonadMask
] class.
这非常不方便,因为 MonadMask
使我们能够访问有用的 [多态版本] bracket
函数来进行资源管理(不会由于异常等而泄漏资源)。 )。但在 Servant 的 Handler
monad 中我们无法使用它。
我对此不太熟悉,但有人说解决方案是使用 monad-control
,它有很多合作伙伴库,例如 lifted-base
和 lifted-async
使您的 monad 能够访问 bracket
等资源管理工具(大概这也适用于 ExceptT err IO
和 friend ?)。
但是,monad-control
似乎是 losing favor in the community ,但我不知道替代方案是什么。甚至 Snoyman 最近的 safe-exceptions
库也使用 Kmett 的 exceptions
库并避免 monad-control
。
有人可以为像我这样试图认真使用 Haskell 的人澄清当前的故事吗?
最佳答案
您可以在IO
中工作,在最后返回一个IO(Either ServantErr r)
类型的值并将其包装在ExceptT
中使其适合处理程序类型。这将使您可以在 IO
中正常使用 bracket
。这种方法的一个问题是您失去了 ExceptT
提供的“自动错误管理”功能。也就是说,如果您在处理程序中间失败,则必须对 Either
以及类似的事情执行显式模式匹配。
上面基本上是重新实现ExceptT
的MonadTransControl
实例,即
instance MonadTransControl (ExceptT e) where
type StT (ExceptT e) a = Either e a
liftWith f = ExceptT $ liftM return $ f $ runExceptT
restoreT = ExceptT
monad-control 在提升像 bracket
这样的函数时工作正常,但它有一些奇怪的极端情况,函数如下(摘自 this blog post ):
import Control.Monad.Trans.Control
callTwice :: IO a -> IO a
callTwice action = action >> action
callTwice' :: ExceptT () IO () -> ExceptT () IO ()
callTwice' = liftBaseOp_ callTwice
如果我们传递给 callTwice'
一个打印某些内容的操作,然后立即失败
main :: IO ()
main = do
let printAndFail = lift (putStrLn "foo") >> throwE ()
runExceptT (callTwice' printAndFail) >>= print
无论如何,它都会打印“foo”两次,即使我们的直觉表明它应该在第一次执行操作失败后停止。
<小时/>另一种方法是使用 resourcet
库并在 ExceptT ServantErr (ResourceT IO) r
monad 中工作。您需要使用 resourcet
函数,例如 allocate
而不是 bracket
,并在末尾调整 monad,如:
import Control.Monad.Trans.Resource
import Control.Monad.Trans.Except
adapt :: ExceptT ServantErr (ResourceT IO) r -> ExceptT err IO r
adapt = ExceptT . runResourceT . runExceptT
或类似:
import Control.Monad.Morph
adapt' :: ExceptT err (ResourceT IO) r -> ExceptT err IO r
adapt' = hoist runResourceT
关于haskell - 在像 exceptT a IO 这样的 monad 堆栈中管理资源的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40372087/
我是一名优秀的程序员,十分优秀!