throwE и catchE с монадой ExceptT в нижней части монадического стека - PullRequest
1 голос
/ 26 апреля 2019

Скажем, у меня есть монадический стек, подобный этому:

import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except
import Control.Monad.Trans

type MyMonad = ReaderT Env (ExceptT String IO) -- Env is irrelevant

И функция (упрощенная, но идея верна):

f :: Integer -> MyMonad Integer
f 42 = lift $ throwE "42 is an ILLEGAL number"
f n = return n

То, что я сейчас хочу сделать, это вызватьf из другой функции, но перехватывает выброшенное исключение, если оно возникает, и каким-то образом обрабатывает его (например, выдает другое исключение, но с измененным сообщением).Мне трудно понять, какие операции подъема должны быть выполнены здесь, чтобы это было сделано правильно.Я попробовал что-то вроде этого:

g n = do
  x <- (f n) `catchE'` (\_ -> lift $ throwE "nope, still illegal")
  return x
where catchE' - lift . catchE

, но это, очевидно, не сработает, потому что catchE' берет что-то в монаде ExceptT, а не MyMonad.Это можно сделать легко?Возможно, поможет изменение структуры стека монад?

1 Ответ

3 голосов
/ 26 апреля 2019

Вам нужно больше lift, чтобы поднять catch через монадный трансформатор. Фактически, существуют трансформаторы, которые вообще не могут поднять catch (например, ContT). Однако для ReaderT есть, и самый простой способ использовать это через Control.Monad.Error.catchError из библиотеки mtl.

...