
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 with 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/. :-)