Почему вам не нужно использовать 'lift' при взаимодействии с вложенным Монадтом StateT в этом случае?
скажем, у меня есть monadT:
type Wrap a = ReaderT Env ( StateT Int ( StateT Int Identity ) ) a
здесь важно отметить, что один StateT обертывает другой, и оба завернуты внутри третьей монады, а именно ReaderT.
и соответствующая функция runWrap для удобства:
type Env = Map.Map Char Integer
runWrap :: Env -> Int -> Int -> Wrap a -> a
runWrap env st1 st2 m = runIdentity $ evalStateT ( evalStateT ( runReaderT m env ) st2 ) st1
и общая монада состояния тока:
tock :: (Num s, MonadState s m) => m ()
tock = do modify (+1)
я теперь с запахом monadT, где внутри я использую так:
aWrap :: Wrap ( Int, Int )
aWrap = do
lift tock
lift . lift $ tock
x <- get
y <- lift . lift $ get
return ( x, y )
и запустить его:
env = Map.fromList [('x', 1)]
runWrap env 1 200 aWrap
// answer: (201,2)
использование из lift
здесь имеет смысл для меня с точки зрения моего понимания того, как взаимодействовать с вложенными слоями Монадта.
однако это также работает и дает мне тот же ответ:(201,2)
:
aWrap :: Wrap ( Int, Int )
aWrap = do
tock
lift . lift $ tock
x <- get
y <- lift . lift $ get
return ( x, y )
я бы подумал, позвонив tock
Вт/lift
, он читается как tock
применяется для наружных MonadT, а именно ReaderT, что не имеет никакого смысла. Но почему это работает?
P. S. пожалуйста, игнорировать присутствие Env
здесь, это не имеет ничего общего с вопросом, просто выбор внешнего MonadT я использую.
1 ответов
скорее всего, вы используете MonadState
typeclass, не осознавая этого. Этот typeclass определена в (и monads-fd
тоже).
MonadState
позволяет использовать методы State
монада, непосредственно и без явного подъема, во многих стеках монады на основе State
.
посмотрите на следующие две строки в рода хаддоков:
Monad m => MonadState s (StateT s m)
MonadState s m => MonadState s (ReaderT r m)
первый говорит, что любой StateT
пример MonadState
(как и следовало ожидать!). Второй говорит, что любой ReaderT
чья базовая монада является instace MonadState
, также является экземпляром MonadState
. И это как раз твое дело.
смотреть на!--28-->исходный код на MonadState
, мы находим:
instance MonadState s m => MonadState s (ReaderT r m) where
get = lift get
put = lift . put
state = lift . state
modify :: MonadState s m => (s -> s) -> m ()
modify f = state (\s -> ((), f s))
как вы видите, внутренний механизм typeclass заботится о подъеме.
есть другие typeclasses, которые предлагают аналогичную функциональность, как MonadReader
, MonadWriter
и MonadRWS
.