我正在尝试将 Control.Exception.Safe
与 Control.Monad.Except
一起使用。
throwString "Foo" :: Except String a
-- error, no instance for `MonadTrow Identity`
好吧,显然 Except
将其错误抛出到变压器堆栈中的底层 monad 中?
但这是为什么呢? Except
基本上不就是为了处理异常而设计的吗?为什么会有这种奇怪的行为?为什么不是 Left "Foo"
编辑:
可以进一步说明我的问题:
我认为 ExceptT e m a
与 Either e a
的关系就像 ReaderT a m b
与 a -> b
的关系一样。 Control.Monad.Except.throwError
和 catchError
的工作方式与 Control.Exception.Safe.throw
和 catch
完全相同> 用 Eather e a
来做。
然而,当它们应用于 Except e a
时,它们的工作方式突然不同了。
当我想在 monad 转换器的上下文中使用 Control.Exception.Safe
提供的 Either e a
行为时,我该怎么办?
我的背景是,我“在 48 小时内为自己编写一个方案”,并希望概括错误(使用 MonadThrow
),以便我可以用它做一些 IO 操作。
编辑2:
示例:
data CountError = CountError deriving (Show, Except)
x :: String -> ExceptT CountError (Writer [String]) Int
x str = do { lift $ writer (length "str", return str); }
现在,这将计算字符数并收集写入器中的字符串。这可以根据您的需要延长。该错误可能表示“字符串中的字符错误”,或“字符太多”,或其他任何信号。
y :: MonadThrow m => m a
y = throw CountError
这是一个非常普遍的异常,我可以将其用于与任何其他类型的异常组合,但 ExceptT
除外:
y >> x
-- No instance for MonadThrow Identity
-- But what I want is (Left CountError, [])
最佳答案
Ok, so apparently Except throws its error into its underlying monad in the transformer stack?
正如我在评论中所说: except 不会“将错误扔到底层 monad 中”,这正是 MonadThrow 实例正在做的事情。
But why is that?
MonadThrow 的实例不能将所有类型 e
的 String 异常抛出到 ExceptT e
中,而不是只为 ExceptT String
提供一个实例> 看来作者在下一个更高的 monad 上引发了异常。
Isn't Except basically designed to handle exceptions?
事实上,Except
的设计目的是允许在特殊情况下发生故障。
作为迂腐的人,我将其称为异常的替代方案。一个 monad 管道了另一种返回概念(错误情况)并称自己为“Except”,实际上并不意味着正在使用任何典型的异常选项,例如低级堆栈展开。
Why this weird behavior?
因为 MonadThrow 实例是从 Control.Monad.Throw
重新导出的:
-- | Throws exceptions into the base monad.
instance MonadThrow m => MonadThrow (ExceptT e m) where
throwM = lift . throwM
Why not the equivalent of Left "Foo"
因为这样实例就必须是 ExceptT String
而不是 ExceptT e
。或者,这就是为什么我认为异常(exception)
(Edward Kmett) 的作者决定采用这种设计。
相反,请考虑使用 Control.Monad.Except.throwError
,它可以实现您想要的功能。
What do I do, when I want to use the behaviour of
Either e a
that is supplied by Control.Exception.Safe but in the context of monad transformers?
您在谈论什么“Either e a
”行为?您正在寻找的内容与throwError
有何不同?据我所知,您正在寻找不必要的额外抽象层。
关于haskell - Control.Exception.Safe,为什么 exceptT 和 Either 的行为如此不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48029125/