为什么模式匹配失败没有被异常处理程序捕获?
Why a pattern-matching failure is not catching by the exception handler?
在这种情况下,为什么我的异常处理程序 excToStr
没有捕捉到模式匹配失败?
我有一个传入的 POST 请求的处理程序,在 Scotty Web framework:
的控制下
...
import qualified Web.Scotty as W
...
W.post "/some/endpoint" $ excToStr "Cannot handle it!" $ do
b <- W.body
-- throwString "aaa" <--- THIS IS HANDLED FINE!
Just x::Maybe SomeMyType <- pure (decode b) -- BUT NOT THIS PATTERN-MATCHING FAILURE!
liftIO $ print $ show x
W.text "OK"
其中 excToStr
是我的,看起来像:
...
import qualified Data.Text.Lazy as LT
...
excH :: (String -> String) -> ActionT LT.Text IO () -> ActionT LT.Text IO ()
excH mkErr m = catchAnyDeep m (W.text . cs . mkErr . show)
excToStr :: String -> ActionT LT.Text IO () -> ActionT LT.Text IO ()
excToStr errMsg = excH (\details -> errMsg <> " (" <> details <> ")")
catchAnyDeep
来自 safe-exceptions 图书馆。我也尝试了其他功能(catchAny
、handle
、catch
等)- 但没有成功。问题的症结在于,当传入的正文无法成功解码时(并且 decode
returns Nothing
而不是 Just x
),则模式匹配失败,所以我预计我的 extToStr
(即 excH
)会处理它,因为 catchAnyDeep
(和 catchAny
)处理 ANY 异常(包括模式匹配失败,对吗?):
catchAny :: MonadCatch m => m a -> (SomeException -> m a) -> m a
和
catchAnyDeep :: (MonadCatch m, MonadIO m, NFData a) => m a -> (SomeException -> m a) -> m a
.
如果我用 throwString
抛出一个异常,那么它会按预期工作(异常被捕获)。但是模式匹配失败会导致 HTTP 内部错误 500,并显示消息“在 do 表达式中模式匹配失败......”。如何处理模式匹配异常?
scotty 操作(ActionT Text IO
类型)中有两种形式的异常。 IO
中有原生异常,ActionT
转换器添加了另一种形式。这些异常是单独处理的。接口由 the instances of ActionT
:
给出
(MonadCatch m, ScottyError e) => MonadCatch (ActionT e m)
(和 MonadThrow
实例类似)。这表明,当您使用 MonadCatch
中的 catch
(或 MonadThrow
中的 throwString
,以及 safe-exceptions[=44= 中的其他变体时] 库),你正在使用转换后的 monad m
的错误处理机制,在 Scotty 中通常是 IO
(它定义 ActionM = ActionT Text IO
)。
(Monad m, ScottyError e) => MonadFail (ActionT e m)
。 MonadFail
是用于 do
块中部分 pattern-matches 的约束。它不需要来自底层 monad m
的 MonadFail
,这表明与 MonadThrow
/MonadCatch
不同,它使用 ActionT
提供的异常机制变压器本身。要捕获此异常,您必须在 Scotty 中寻找组合器而不是辅助库,例如 rescue
.
在这种情况下,为什么我的异常处理程序 excToStr
没有捕捉到模式匹配失败?
我有一个传入的 POST 请求的处理程序,在 Scotty Web framework:
的控制下...
import qualified Web.Scotty as W
...
W.post "/some/endpoint" $ excToStr "Cannot handle it!" $ do
b <- W.body
-- throwString "aaa" <--- THIS IS HANDLED FINE!
Just x::Maybe SomeMyType <- pure (decode b) -- BUT NOT THIS PATTERN-MATCHING FAILURE!
liftIO $ print $ show x
W.text "OK"
其中 excToStr
是我的,看起来像:
...
import qualified Data.Text.Lazy as LT
...
excH :: (String -> String) -> ActionT LT.Text IO () -> ActionT LT.Text IO ()
excH mkErr m = catchAnyDeep m (W.text . cs . mkErr . show)
excToStr :: String -> ActionT LT.Text IO () -> ActionT LT.Text IO ()
excToStr errMsg = excH (\details -> errMsg <> " (" <> details <> ")")
catchAnyDeep
来自 safe-exceptions 图书馆。我也尝试了其他功能(catchAny
、handle
、catch
等)- 但没有成功。问题的症结在于,当传入的正文无法成功解码时(并且 decode
returns Nothing
而不是 Just x
),则模式匹配失败,所以我预计我的 extToStr
(即 excH
)会处理它,因为 catchAnyDeep
(和 catchAny
)处理 ANY 异常(包括模式匹配失败,对吗?):
catchAny :: MonadCatch m => m a -> (SomeException -> m a) -> m a
和
catchAnyDeep :: (MonadCatch m, MonadIO m, NFData a) => m a -> (SomeException -> m a) -> m a
.
如果我用 throwString
抛出一个异常,那么它会按预期工作(异常被捕获)。但是模式匹配失败会导致 HTTP 内部错误 500,并显示消息“在 do 表达式中模式匹配失败......”。如何处理模式匹配异常?
scotty 操作(ActionT Text IO
类型)中有两种形式的异常。 IO
中有原生异常,ActionT
转换器添加了另一种形式。这些异常是单独处理的。接口由 the instances of ActionT
:
(MonadCatch m, ScottyError e) => MonadCatch (ActionT e m)
(和MonadThrow
实例类似)。这表明,当您使用MonadCatch
中的catch
(或MonadThrow
中的throwString
,以及 safe-exceptions[=44= 中的其他变体时] 库),你正在使用转换后的 monadm
的错误处理机制,在 Scotty 中通常是IO
(它定义ActionM = ActionT Text IO
)。(Monad m, ScottyError e) => MonadFail (ActionT e m)
。MonadFail
是用于do
块中部分 pattern-matches 的约束。它不需要来自底层 monadm
的MonadFail
,这表明与MonadThrow
/MonadCatch
不同,它使用ActionT
提供的异常机制变压器本身。要捕获此异常,您必须在 Scotty 中寻找组合器而不是辅助库,例如rescue
.