是否可以提供类型
的表达式MonadError e m => m ()
会引发错误,可以使用catchError
处理?请注意,缺少Error e
要求。
在fail
下使用catchError
创建的错误在什么情况下可以处理?什么可能导致fail
没有被catchError
抓住?这些情况在GHC发布方面有何变化? (在基础4.3中,行为发生了变化mention。)
此问题的背景是一段较大的代码(Igor2函数nomatch
),其中使用fail "some message"
创建的错误经过catchError
并终止程序,但用fail
替换throwError undefined
调用会导致错误被捕获。当然throwError undefined
是一个丑陋的黑客,这个问题旨在了解背景和正确的解决方案。
答案 0 :(得分:3)
这里有几个不同的问题,所以我会按顺序完成它们。
MonadError e m => m ()
上述问题是,如果e
没有受到任何限制,则无法为e
创建throwError
类型的值throwError undefined
。所以不,上述类型引发错误的唯一有效值需要包括
Error e
这是一个警察(并不是很有用)。 e
约束允许您通过提供从字符串构造类型e
的值的机制来保留MonadError
摘要。
在什么情况下可以使用catchError处理失败时创建的错误?什么可能导致失败没有被catchError捕获?
这完全取决于有问题的monad。 fail
的不同实例可能对fail
具有不同的实现,因此没有通用答案。换句话说,除非您使用catchError
的特定实例来实现该承诺,否则无法保证MonadError
可以处理由{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Error
example :: (Error e, MonadError e m) => m String
example = fail "This is a failure" `catchError` const (return "Error was caught")
main = do
example >>= putStrLn
either putStrLn putStrLn example
触发的错误。例如:
main
在example
的第一行,MonadError
使用IO
的{{1}}实例,第二行使用MonadError
的{{1}}实例}。 Either String
导致fail
中的可捕获错误,但IO
中未导致错误,因此程序输出
Either
但是,如果我们用
替换Error was caught
*** Exception: This is a failure
example
然后我们得到所需的输出
example :: (Error e, MonadError e m) => m String
example = throwError (strMsg "This is a failure")
`catchError` const (return "Error was caught")
对于任何(有效)Error was caught
Error was caught
实例,这与MonadError
不同。
这些情况在GHC发布方面有何变化? (有人提到基础4.3中的行为发生了变化。)
基数4.3的变化是指fail
monad中fail
的工作原理。在以前的版本中,Either
返回了一个fail
值,该值可以在Left
中捕获但在4.3中使用error
并触发必须在{{{}处理的异常1}}(例如catch
)。
Igor2中的问题听起来像它使用catchError
monad并假设IO
应该使用Either
时的旧行为(如果有fail
则简单throwError
没有合适的Left
实例)。