DEV Community

Chris Wendt
Chris Wendt

Posted on

What if runST didn't use existential quantification?

Here's the ST API:

data ST s a

runST :: (forall s. ST s a) -> a
newSTRef :: a -> ST s (STRef s a)
readSTRef :: STRef s a -> ST s a
writeSTRef :: STRef s a -> a -> ST s ()
Enter fullscreen mode Exit fullscreen mode

Let's drop forall s and see what happens:

data ST s a

runST :: ST s a -> a
newSTRef :: a -> ST s (STRef s a)
readSTRef :: STRef s a -> ST s a
writeSTRef :: STRef s a -> a -> ST s ()
Enter fullscreen mode Exit fullscreen mode

Well, now ST can be eliminated by calling runST after any other operation (e.g. runST . newSTRef):

newSTRef :: a -> STRef s a
readSTRef :: STRef s a -> a
writeSTRef :: STRef s a -> a -> ()
Enter fullscreen mode Exit fullscreen mode

At the type level, writeSTRef looks useless, but it still has the side effect of writing a value to an STRef.

Now the order of evaluation matters, and purity goes out the window:

let ref = newSTRef "1"
    _ = writeSTRef ref "2"
in readSTRef ref -- Does this evaluate to "1" or "2"?
Enter fullscreen mode Exit fullscreen mode

forall s is the linchpin that enforces sequential reads/writes in the ST monad.

Top comments (0)