#haskell #exception #scotty
#haskell #исключение #скотти
Вопрос:
Почему ошибка сопоставления с образцом не улавливается моим обработчиком исключений 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
из библиотеки безопасных исключений. Я также пробовал другие функции ( catchAny
, handle
, catch
, и т. Д.) — Без успеха. Суть проблемы в том, что когда входящее тело не может быть успешно декодировано (и decode
возвращается Nothing
вместо Just x
), тогда сопоставление с образцом завершается неудачно, поэтому я ожидаю, что мой extToStr
(т.е. excH
) обработает это, потому catchAnyDeep
что (и catchAny
) обрабатывает ЛЮБОЕ исключение (включая ошибки сопоставления с образцом, верно?):
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 в ….». Как также обрабатывать исключения сопоставления с образцом?
Ответ №1:
В действии Скотти (типа ) есть две формы исключений ActionT Text IO
. Есть собственные исключения в IO
, и другая форма, добавленная ActionT
преобразователем. Эти исключения обрабатываются отдельно. Интерфейс задается экземплярами ActionT
:
-
(MonadCatch m, ScottyError e) => MonadCatch (ActionT e m)
(и аналогичноMonadThrow
экземпляру). Это показывает, что когда вы используетеcatch
fromMonadCatch
(илиthrowString
fromMonadThrow
и другие варианты из библиотеки безопасных исключений), вы используете механизм обработки ошибок преобразованной монадыm
, который в Scotty обычноIO
(он определяетActionM = ActionT Text IO
). -
(Monad m, ScottyError e) => MonadFail (ActionT e m)
.MonadFail
используется ли ограничение для частичных совпадений с образцом вdo
блоках. Он не требует aMonadFail
от базовой монадыm
, что указывает на то, что, в отличиеMonadThrow
от /MonadCatch
, он использует механизм исключения, предоставляемый самимActionT
преобразователем. Чтобы перехватить это исключение, вы должны искать комбинатор в Scotty, а не вспомогательную библиотеку, такую какrescue
.