Результат монады внутри преобразователя монад

Это мое первое знакомство с Monad Transformers, поэтому ответ может быть очевиден.

Допустим, я нахожусь внутри блока do типа StateT MyMonad MyType, я хочу, чтобы другая функция того же типа изменяла состояние и возвращала значение типа MyMonad MyType. Как я могу этого добиться? Я думаю, что примеры, здесь, показывают это в guessSession, но я не понимаю, как применить Это!


person aelguindy    schedule 20.01.2012    source источник
comment
Если вы не знаете о hoogle: haskell.org/hoogle   -  person jberryman    schedule 20.01.2012


Ответы (1)


Если вы хотите использовать базовую монаду в преобразователе монад, вы можете использовать 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
comment
Я думаю, что понял. Просто чтобы быть предельно ясным. Представьте, что я сделал ‹- doSomethingInMyMonad 42 перед добавлением StateT. Теперь я делаю ‹- поднимаю $ doSomethingInMyMonad 42. Верно? - person aelguindy; 20.01.2012
comment
@aelguindy: Ага! Если у вас есть часть кода, в которой используется только MyMonad, вы также можете поднять целый блок do: lift $ do .... - person ehird; 20.01.2012
comment
Спасибо! Не уверен, что это правильное место, чтобы спросить, но есть ли эквивалент lift, но с двумя аргументами, lift2? Глупый вопрос! Нашел ответ - person aelguindy; 20.01.2012
comment
@aelguindy: Что бы он сделал? Если вы хотите использовать такую ​​функцию, как f :: T1 -> T2 -> MyMonad T3, вы можете просто выполнить lift (f a b) (эквивалентно: lift $ f a b). lift вообще не поднимает функций, а только монадические вычисления. - person ehird; 20.01.2012
comment
Собирался сказать, что придумал! Спасибо еще раз :-). Думаю, теперь я полностью понимаю! - person aelguindy; 20.01.2012