Подумалось мне про трансформеры монад, что если у нас есть натуральные преобразования из монад m и n в некую монаду l, то l - это их сумма, если добавить ещё и обратную функцию. Т.е. при наличии натурального преобразования m => t и n => t можем получить и m+n => t.
Попробовал я это представить прямо в таком виде:
data MonadSum m n a = MonadSum {
monadSum :: forall t. (Monad t) => (forall b. m b -> t b) -> (forall c. n c -> t c) -> t a }
И вот, что получилось:
maybeIO :: Maybe a -> StateT s IO a
maybeIO Nothing = error "Nothing"
maybeIO (Just v) = return v
eitherIO :: Either String a -> StateT s IO a
eitherIO (Left e) = error e
eitherIO (Right v) = return v
stateIO :: State s a -> StateT s IO a
stateIO act = StateT $ return . runState act
bla :: MonadSum Maybe (MonadSum (Either String) (State Int)) String
bla = do
n <- liftR $ liftR get
case n of
0 -> liftL Nothing
1 -> liftR $ liftL $ Left "Error"
2 -> liftR $ liftL $ Right "Ok!"
_ -> do
liftR $ liftR $ put (n `div` 2)
s <- bla
return $ show n ++ s
testBla :: Int -> IO String
testBla = evalStateT $ unlift maybeIO (unlift eitherIO stateIO) bla
Запуск:
*MonadSum> testBla 0
*** Exception: Nothing
*MonadSum> testBla 1
*** Exception: Error
*MonadSum> testBla 2
"Ok!"
*MonadSum> testBla 3
*** Exception: Error
*MonadSum> testBla 4
"4Ok!"
*MonadSum> testBla 8
"84Ok!"
*MonadSum> testBla 7
*** Exception: Error
Полный код
тут.