6

一般的なテーマ: モナドを積み重ねるというアイデアは非常に魅力的ですが、コードがどのように実行されるか、レイヤーを実行する適切な順序を理解するのに苦労しています。以下は、スタックの一例です: 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) ?

4

1 に答える 1