
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
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
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 Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe