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


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to