Arnaud, You might also consider writing monad-agnostic code: code that doesn't know which monad it is executing in.
For example: >class (Monad g) => MonadGit g where > gitOp1 :: .... > gitOp2 :: .... > .... > >instance MonadGit Git where > gitOp1 = ... > gitOp2 = ... > ... > >intance MonadGit DebugGit where > gitOp1 = ... > gitOp2 = ... > >otherGitOp :: (MonadGit g) => a -> b -> g a >otherGitOp = gitOp1 . gitOp2 . otherF . etc In other words, you create a typeclass that (at least) two different monads will implement. One which runs the code normally, while the other performs the debug actions that you described. Then your "debug flag" becomes a choice of which monad to begin execution in. Note that this can be a bit cumbersome (but I don't think impossible) if the debug flag has to be changed at runtime. Hope this helps, --Jonathan On Tue, Sep 28, 2010 at 12:56 AM, Arnaud Bailly <[email protected]> wrote: > Hello Cafe, > > I have the following type which represents some action using Git > >> newtype (Monad m) => Git m a = Git { runGit :: ErrorT String (StateT >> Environment m) a } >> deriving (Monad, MonadState Environment, MonadError String) > > and the following typeclass whose purpose is to abstract away the > details of executing commands in the OS, with an obvious IO instance, > and to ease testing of commands effects: > >> -- | A monad for simple execution of a process within the >> class (MonadError e m) => MonadExec e m where >> debug :: String -> m () >> exec :: String -> [String] -> m String >> -- ^Do not really execute commande but output the command string and >> arguments passed >> exec' :: String -> [String] -> m String >> exec' proc args = return $ program proc args > > The type environment is : > >> data Environment = Env { debugMode :: Bool, >> baseDirectory :: FilePath, >> maven :: FilePath, >> git :: FilePath, >> p4 :: FilePath, >> javaHome :: FilePath} >> deriving (Eq, Show, Read) > > This follows the monad stack pattern presented in RWH and in Don > Stewart's presentation on scripting with haskell. Actually, what I am > trying to achieve is to be able to write my own scripts in Haskell. > > What I would like to do is to be able to wrap each Git action occuring > in a MonadExec instance into a call to debug according to the status > of the debugMode flag in environment, in order to prevent the need of > explicit calls to debug. Something like the -v flag in bash... > > I can imagine being able to do this using 2 different ways: > - add a constraint on Git monad and write explicitly return and >>= > to use debug > - push the environment or part of it inside the MonadExec, for > example as a Reader. > > What is the "best" (i.e. most economical) way of doing this? > > Thanks for your advices. > > Arnaud Bailly > _______________________________________________ > Haskell-Cafe mailing list > [email protected] > http://www.haskell.org/mailman/listinfo/haskell-cafe > _______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
