Combining distinct-thread state monads?

Graham Klyne GK at ninebynine.org
Tue Jan 6 12:28:30 EST 2004


[Reply thread moved to Haskell-cafe]

At 18:19 06/01/04 +1030, Dr Mark H Phillips wrote:
>I am still learning about monads.  I have a problem
>in mind and am wondering whether state monads are
>able to solve it.  The difficulty is that it would
>necessitate the interaction of two state threads
>and I'm not sure whether Haskell state monads
>allow this.  Let me explain what I'm getting at.

I'm not an expert in this, but I think what you are proposing is possible, 
to a point, possibly assuming that your monads have associated functions to 
combine and separate the monadic parts.

Hmmm, let's try something...

Given:

   combine  :: ma -> mb -> mab
   separate :: mab -> (ma,mb)

(where ma, mb, mab are the separate and combined state monads)

   f :: ma () -> mb () -> mc ()
   f a b =
     do { ma1 <- fa1 a  -- process state in a, returning ma1
                        -- fa1 :: ma -> mc ma
        ; mb1 <- fb1 b  -- process state in b, returning mb1
        ; let mab1 = combine ma1 mb1
        ; mab2 = fab mab1
        ; let (ma2,mb2) = separate mab2
        ; ma3 <- fa3 ma2  -- process state in ma2
        ; mb3 <- fb3 mb2  -- process state in mb2
        ; return (fc ma3 mb3)
        }

(This code is speculative, not tested in any way.)

In this case, a third monad is used to schedule the operations on the 
separate monads, so in that respect the entire sequence is performed in a 
composite monad, within which methods defined for the separate monads can 
be invoked.
To get the results, Monad 'mc' would need to provide a way to pick them out.

It looks as if the combined monad 'mab' is probably superfluous.  I think 
the composite monad 'mc' might be avoided, but some of the efficiency 
advantage of monads would be lost as the single-threading of each monad is 
potentially broken.

I think that this may be all be achieved more cleanly using the monad 
transformer libraries and 'lift' methods -- can a state transformer be 
applied to a state monad?

What I have noticed in my work with monads is that in most respects they 
can be treated just like any other value.  Although they look different, a 
do sequence is just a monad-returning function, and any monad-returning 
function may be a do sequence.

<aside>
In my own work, I was pleasantly surprised how easy it was to use a Parsec 
parser monad (effectively a state monad, I think) to parse some data and 
return a combined state+IO monad, effectively precompiling a script, which 
which could then be executed by applying the resulting monad to an initial 
state, all within an IO monad.  The code which does this can be seen at:
   http://www.ninebynine.org/Software/Swish-0.2.0/SwishScript.hs

The main parser declaration is:
   script :: N3Parser [SwishStateIO ()]
where 'script' is a Parsec parser monad which parses a script and returns a 
list of 'SwishStateIO ()' values, each of which is a combined state+IO monad.
</aside>

#g
--

>Consider two state threads.  The first has each state
>being a non-negative int, thought of as a string of
>binary digits.  The second thread has each state
>being a bool.
>
>Now I want to have a state monad which modifies
>both threads as follows.  Consider input states i (the
>int thought of as binary string) and b (the bool),
>and output states i' and b'.
>
>   b' = not (b && (i `mod` 2))
>   i' = i `div` 2
>
>As you can see, both of these should be able to do
>update-in-place provided the above order is adhered to.
>We could achieve this using state monads where state
>is an (Int, Bool) pair.  We would have one monad
>which did the first line, leaving i unchanged and
>a second monad which did the second line, leaving
>b' unchanged.
>
>But... what if before this interaction, the int
>thread and the bool thread were separate monads
>doing their own thing, and we just wanted to
>combine these threads briefly (using the above
>interaction) before letting the threads do their
>own thing again?  Is this possible?
>
>Also, suppose we have previously defined an int thread
>monad which takes i, returns a value of i `mod` 2,
>and changes the state to i' = i `div` 2.  Suppose
>also we have previously defined a bool thread
>monad which takes b, returns a nothing value, and
>changes the state to b' = not b.  Can we use
>these two monads (each acting on different
>threads), to form a combined-interaction monad
>that does (same as before):
>
>   b' = not (b && (i `mod` 2))
>   i' = i `div` 2
>
>I hope this is possible.  It would facilitate
>both code reuse and readability.  However I
>fear that it is not, requiring one to instead
>explicitly rewrite the two separate thread monads
>into (Int, Bool) pair acting ones.
>
>Cheers,
>
>Mark.
>
>
>_______________________________________________
>Haskell mailing list
>Haskell at haskell.org
>http://www.haskell.org/mailman/listinfo/haskell

------------
Graham Klyne
For email:
http://www.ninebynine.org/#Contact



More information about the Haskell-Cafe mailing list