[Haskell-cafe] IO and State

Ben Rudiak-Gould Benjamin.Rudiak-Gould at cl.cam.ac.uk
Thu Nov 11 10:57:42 EST 2004

Iavor S. Diatchki wrote:

> In GHC the whole program stops when the main thread exits.
> So if the law I was talking about holds, this program should
> never terminate, as it will forever loop in 'reader'.
> However since there is a concurrent thread running that can modify
> the state, if 'reader' is interrupted between the two readSTRefs
> we will get different values for 'x' and 'y' and 'reader' will stop.
> I tried that in GHC and it stops after a little while, so the law does 
> not hold.

I would say that the law holds in one direction and not the other. It's 
safe to replace

    do x <- readSTRef r
       y <- readSTRef r


    do x <- readSTRef r
       let y = x

but not the other way around. The semantics for concurrency don't 
guarantee that a task switch will /never/ happen between two calls of 
readIORef, but they don't guarantee that a task switch will /ever/ 
happen, either, so relying on your sample application terminating is 
non-portable. Therefore optimizing it in such a way that it never 
terminates is safe.

If it's important to distinguish ST actions which can be treated as IO 
from others which can't, you can introduce a type class

    class PrivateState s where {}

and a new function

    newPureSTRef :: forall a s. PrivateState s => a -> ST s (Ref s a)
    newPureSTRef = newRef

There don't need to be any instances of PrivateState; the only important 
thing is that RealWorld isn't an instance. Any code which uses a Ref 
created by newPureSTRef is restricted to the PrivateState space and 
therefore can't be used as part of an IO action. runST would be given 
the more general type

    runST :: forall a. (forall s. PrivateState s => ST s a) -> a

which would work for pure ST and ordinary (IO-embeddable) ST actions. 
stToIO would retain its current type, and so would not work with pure ST 
actions. Your equivalence would apply in both directions to any action 
of type (forall s. PrivateState s => ST s a).

I don't think this careful approach is necessary in practice, but I hope 
the fact that it can be done [*] makes the merging of ST and IO look 
more reasonable.

-- Ben

[*] Except how would you prevent the user from declaring an instance for 
PrivateState RealWorld? Oh well. It can be done /in principle/. :-)

More information about the Haskell-Cafe mailing list