[Haskell-cafe] Stacking monads - beginner design question

Adam Smyczek adam.smyczek at gmail.com
Wed Jan 30 02:22:57 EST 2008


It works like a charm,
thanks a lot Jonathan!

Adam



On Jan 29, 2008, at 10:26 PM, Jonathan Cast wrote:

> On 29 Jan 2008, at 9:44 PM, Adam Smyczek wrote:
>
>> Hi,
>>
>> My application has to manage a data set. I assume the state monad  
>> is designed for this.
>> The state changes in functions that:
>> a. perform IO actions and
>> b. return execution status and execution trace (right now I'm  
>> using WriteT for this).
>>
>> Is the best solution:
>> 1. to build a monad stack (for example State -> Writer -> IO) or
>> 2. to use IORef for the data set or
>> 3. something else?
>>
>> Are monad stacks with 3 and more monads common?
>
> I'd say they're fairly common, yes; at least, they don't jump out  
> at me as bad style (especially when the monads are fairly  
> orthogonal, as here).
>
>> How could an example implementation look like?
>
> newtype Program alpha
>   = Program { runProgram :: StateT Config (WriterT [String] IO)  
> alpha }
>   deriving (Functor, Monad, MonadWriter, MonadState)
>
>>
>> What I have for now is:
>>
>> -- Status
>> data Status = OK | FAILED deriving (Show, Read, Enum)
>>
>> -- Example data set manages by state
>> type Config = [String]
>>
>> -- WriterT transformer
>> type OutputWriter = WriterT [String] IO Status
>>
>> -- example execute function
>> execute :: [String] -> OutputWriter
>
> execute :: [String] -> Program Status
>
>> execute fs = do
>> 	rs <- liftIO loadData fs
>> 	tell $ map show rs
>> 	return OK
>>
>> -- run it inside e.g. main
>> (s, os) <- runWriterT $ execute files
>
> (s', (s, os)) <- runWriterT (runStateT (runProgram $ execute files)  
> inputstate)
>
> It's a bit tricky, since you have to write it inside-out, but it  
> should only type check if you've got it right :)
>
>> How do I bring a state into this, for example for:
>> execute fs = do
>> 	?? conf <- get ?? -- get Config from state
>
> Right.
>
>> 	rs <- liftIO loadData conf fs
>> 	?? set conf ?? -- change Config and set to state
>
> Right.
>
>> 	tell "new state:"
>
> Right.
>
>> 	tell $ show conf
>> 	return OK
>>
>> Do I have to use
>
> Depends on what you mean by `have to'.  If you don't want to thread  
> the state yourself, and you don't want to use an IORef, you'll need  
> some implementation of a state monad.  That will have to be in the  
> form of a monad transformer applied to IO, so the easy answer is  
> `yes'.
>
>> and how do I use StateT in this context:
>> data DataState = StateT Config OutputWriter ??
>
> This is parenthesized wrong; the output type goes outside the  
> parentheses around WriterT:
>
> StateT Config (WriterT [String] IO) Status
>
> not
>
> StateT Config (WriterT [String] IO Status)
>
>> and how do I run it runStateT . runWriterT?
>
> Other way 'round, as above.
>
> HTH
>
> jcc
>



More information about the Haskell-Cafe mailing list