gpt4 book ai didi

haskell - 异常和monad转换器

转载 作者:行者123 更新时间:2023-12-04 00:35:04 26 4
gpt4 key购买 nike

我正在使用 EitherT 单子(monad)变压器。将它与 IO monad 结合起来,恐怕我会得到一个异常并且它不会被捕获。

事实上,异常只是通过:

import Control.Monad.Trans
import Control.Error
import System.Directory

main = runEitherT testEx >>= print

testEx :: EitherT String IO ()
testEx = lift $ removeFile "non existing filename"

但是 EitherT否则完全适合向调用者传达错误。所以我想使用它,而不是抛出异常......

我看了 try来自 Control.Exception:
try :: Exception e => IO a -> IO (Either e a) 

它看起来正是我想要的,它适合我的 EitherT IO 堆栈...(可能添加了 hoistEither 和可能 fmapL,但它开始看起来很冗长)但是天真的 lift $ try不进行类型检查。

我确信这个问题已经解决了数千次,但我找不到任何描述这个确切问题的好链接。这应该如何解决?

编辑 通过“这应该如何解决”,我对惯用的解决方案很感兴趣,在 haskell 中处理它的标准方法是什么。从到目前为止的答案来看,似乎惯用的方法是让异常被抛出并在更高层处理它们。拥有两个控制流和返回路径似乎有点违反直觉,但这显然是它的本意。

最佳答案

我其实认为EitherT不是在这里做的正确的事情。你想说的是“IO 是针对副作用的,EitherT 是针对异常的。”但这不是真的:IO总是有可能导致异常,所以你所做的只是给你的 API 增加一种错误的安全感,并引入两种可以抛出异常的方法,而不是一种。此外,不要使用结构良好的 SomeException受到IO 的青睐, 你正在减少到 String ,它会丢弃信息。

无论如何,如果您确信这是您想要做的,那并不太难。它看起来像:

eres <- liftIO $ try x
case eres of
Left e -> throwError $ show (e :: SomeException)
Right x -> return x

但是请注意,这也会吞噬异步异常,这通常不是您想要做的。我认为更好的方法是 enclosed-exceptions .

关于haskell - 异常和monad转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25752900/

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