一般的なテーマ: モナドを積み重ねるというアイデアは非常に魅力的ですが、コードがどのように実行されるか、レイヤーを実行する適切な順序を理解するのに苦労しています。以下は、スタックの一例です: Writer、State、State、および Error、順不同 (またはありますか?)。
-----------------------
-- Utility Functions --
-----------------------
type Memory = Map String Int
type Counter = Int
type Log = String
tick :: (MonadState Counter m) => m ()
tick = modify (+1)
record :: (MonadWriter Log m) => Log -> m ()
record msg = tell $ msg ++ "; "
------------------
-- MonadT Stack --
------------------
mStack :: ( MonadTrans t, MonadState Memory m, MonadState Counter (t m), MonadError ErrMsg (t m), MonadWriter Log (t m) ) => t m Int
mStack = do
tick
m <- lift get
let x = fromJust ( M.lookup "x" m ) in x
record "accessed memory"
case True of
True -> return 100
False -> throwError "false"
mStack
エラーがスローされるかどうかは、関数の他の部分とは何の関係もないことに注意してください。
理想的には、出力を次のようにしたいと考えています。
( Right 100, 1, "accessed memory", fromList [...])
または一般的に:
( output of errorT, output of stateT Counter, output of writerT, output of StateT Memory )
しかし、私はそれを機能させることができません。具体的には、エラーが最外層にあるかのようにスタックを実行してみました。
mem1 = M.fromList [("x",10),("y",5)]
runIdentity $ runWriterT (runStateT (runStateT (runErrorT mStack ) 0 ) mem1 ) ""
しかし、このエラーメッセージが表示されます:
Couldn't match type `Int' with `Map [Char] Int'
上記のインスタンスはさておき、一般的に、私が呼び出しているとき:
runMonadT_1 ( runMonadT_2 expr param2 ) param1
、
関連する関数monadT_2
が最初に実行され、次にその出力が関連する関数にパイプされmonadT_1
ますか? 言い換えれば、コードが上記の functionmStack
に見えるのと同じくらい命令的ですが、実行の順序は monadT が実行される順序に完全に依存しています (によって導入された構造の厳格さは別としてlift
) ?