Look rather obvious when explained :-) And this is a pattern I have already used for other code :-(
Thanks a lot Jonathan, that's indeed quite helpful. Regards Arnaud On Tue, Sep 28, 2010 at 3:03 PM, Jonathan Geddes <[email protected]> wrote: > 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
