[Haskell-cafe] Question on monad transformers stack

Arnaud Bailly arnaud.oqube at gmail.com
Tue Sep 28 09:26:51 EDT 2010


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
<geddes.jonathan at gmail.com> 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 <arnaud.oqube at gmail.com> 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 at haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>>
>


More information about the Haskell-Cafe mailing list