Если вы хотите использовать базовую монаду в преобразователе монад, вы можете использовать lift
:
lift :: (MonadTrans t, Monad m) => m a -> t m a
В этом случае t
равно StateT MyState
, а m
равно MyMonad
. Так, например:
foo :: StateT MyState MyMonad MyType
foo = do
modify $ \s -> s+1
lift $ doSomethingInMyMonad 42
Преобразователи монад не являются "наслоенными" в том смысле, что вы должны вернуть значение типа MyMonad MyType
изнутри; это более буквальное преобразование: они превращают монаду в новую, которая может выполнять действия в преобразованной монаде. Итак, вы можете рассматривать StateT s m
как обычную State s
монаду, за исключением того, что вы также можете использовать lift
для выполнения действий поворота в m
в действия в StateT s m
.
Если вы используете стандартные преобразователи библиотеки преобразователей монад (mtl), такие как StateT
, ReaderT
и т. Д. , вам не обязательно использовать lift
; такие вещи, как modify
и ask
, работают в любой монаде с правильным преобразователем где-нибудь в стеке. (Стек - это просто башня преобразованных монад, как StateT s (ReaderT r IO)
.)
Кроме того, если у вас большой стек с IO
внизу, есть удобная функция для поднятия IO
действия на любое количество уровней:
liftIO :: (MonadIO m) => IO a -> m a
Итак, liftIO (putStrLn "Hello, world!")
работает в IO
, StateT Int IO
, ContT r (WriterT [String] IO)
и так далее.
(В качестве дополнительного примечания, foo
здесь на самом деле не функция; более точный термин - действие или вычисление.)
person
ehird
schedule
20.01.2012