General topic: Although I think that the idea of putting monads together is very attractive, I have problems with the image of how the code is executed, and what are the corresponding orders for launching the layers. The following is one example stack: Writer, State, State, and Error, in a specific order (or is there?).
----------------------- -- 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 (tm), MonadError ErrMsg (tm), MonadWriter Log (tm) ) => tm 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"
Note that in mStack , whether an error occurs or not has nothing to do with any other part of the function.
Now, ideally, I want the result to look like this:
( Right 100, 1, "accessed memory", fromList [...])
or even:
( output of errorT, output of stateT Counter, output of writerT, output of StateT Memory )
But I can’t make it work. In particular, I tried to launch the stack as if the error was on the outermost layer:
mem1 = M.fromList [("x",10),("y",5)] runIdentity $ runWriterT (runStateT (runStateT (runErrorT mStack ) 0 ) mem1 ) ""
But I get this error message:
Couldn't match type `Int' with `Map [Char] Int'
The above instance aside, in general, when I call:
runMonadT_1 ( runMonadT_2 expr param2 ) param1 ,
functions related to monadT_2 , then this output is passed to functions related to monadT_1 ? In other words, how is it necessary, since the code looks like in the above mStack function, the order of execution depends entirely on the order in which monadT is executed (except for any rigidity in the structure introduced by lift )?