[Haskell-cafe] Composing functions with runST

Yitzchak Gale gale at sefer.org
Thu Jan 4 05:40:57 EST 2007


I wrote:
>> Combining ST and MTL can be messy, even in this simple
>> case. You will probably write something with a type like
>> RandomGen g => [a] -> g -> ST s ([a], g)

Udo Stenzel wrote:
> But why would you even want to do this?  It's ugly and cumbersome.

Yes indeed.

> You'd plug a runST in there and get
> shuffle :: RandomGen g => [a] -> g -> ([a], g)

Yes. In fact, that is what I did in practice.

As you say, the overall effect is ugly and cumbersome.
And this is with only the simplest of stateful calculations.
I shudder to think about what happens when things are more
complex. That is why I am thinking that -

>> Wouldn't it be nice if instead you could just write:
>>
>> shuffle :: (RandomGen g, MonadState g m) => [a] -> m [a]
>> shuffle = stToState . shuffleST

and then just use that directly inside a calculation that
is otherwise purely non-ST?

> It seems, what you really want is
> shuffleST :: RandomGen g => [a] -> StateT g ST [a]

Actually, I tried that. It didn't help - it was just one more
layer I had to peel away to get at the ST inside.

There seems to be no way to avoid the fact that you
think about state in two very different ways in these
two monads. Every program is written in either one style
or the other. Occasionally, you require an isolated use
of the opposite style, and I am looking for ways of simplifying
the resulting mess. "StateT st ST" and "MonadST" look like
ways of combining the two, but in practice I find that they
just seem to get in the way.

I am starting to be convinced that the only way to
write the function I want is by using unsafeRunST.

Or type it as

stToState :: MonadState st m => (st -> ST s (a, st)) -> m a

and then write in the documentation that the
user is require to write

do
  r <- newSTRef x
  ...
  y <- readSTRef r
  return (z, y)

by hand every time. Yuck.

Am I missing something?

-Yitz


More information about the Haskell-Cafe mailing list