私がmonadTを持っているとしましょう:
type Wrap a = ReaderT Env ( StateT Int ( StateT Int Identity ) ) a
ここで注意すべき重要なことは、1つのStateTが別のStateTをラップしており、両方が3番目のMonadT、つまり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)
ここで、内部でtockを使用するラップ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
、MonadTのネストされたレイヤーと相互作用する方法を理解しているという点で私には理にかなっています。
ただし、これも機能し、同じ答えが得られます(201,2)
::
aWrap :: Wrap ( Int, Int )
aWrap = do
tock
lift . lift $ tock
x <- get
y <- lift . lift $ get
return ( x, y )
tock
w / olift
と呼ぶとtock
、外側のMonadT、つまりReaderTに適用されているように見えますが、これは意味がありません。しかし、なぜこれが機能するのでしょうか?
PSEnv
ここの存在を無視してください、それは質問とは何の関係もありません、ただ私が使用している外側のMonadTの選択だけです。