Только что видел примеры типа
type StateMonad e a = StateT State (Either e) a
и
type MyMonadT e m a = StateT MyState (ExceptT e m) a
но, насколько я понимаю, вы потеряете свое состояние в случае ошибки, потому что здесь вы добавляете состояние внутри Either / Except, поэтому состояние будет доступно только в Right .
Если вам требуется обработать ошибку и получить состояние, которое было вычислено до момента возникновения ошибки, вы можете использовать Кроме T e (State s) a стек:
type StateExcept e s a = ExceptT e (State s) a
test :: Int -> StateExcept String String ()
test limit = do
modify (succ . head >>= (:)) -- takes first char from state and adds next one in alphabet to state
s <- get
when (length s == limit) (throwError $ "State reached limit of " ++ show limit)
runTest :: ExceptT String (State String) () -> (Either String (), [Char])
runTest se = runState (runExceptT se) "a"
λ: runTest (forever $ test 4)
(Left "State reached limit of 4","dcba")
λ: runTest (replicateM_ 2 $ test 4)
(Right (),"cba")