-- This shows why it's important that runST have the higher-rank
-- universal type, rather than the existential type one might
-- expect to suffice. The 'open foo as bar in baz' syntax is
-- intended as a syntax for using a value with an existential
-- type. Within the scope, it is known that 's' is instantiated
-- to some particular; that is, it is known that 's' in the
-- multiple runST's is the same s.
--
-- To mimic this in the actual implementation, unsafeCoerce is
-- needed.
module STBad where
import Control.Monad.ST
import Data.STRef
import Unsafe.Coerce
{-
runST :: exists s. ST s a -> a
bad :: () -> (Int, Int)
bad () = open runST as runST'
in runST' (do r <- newSTRef 0
let x = runST' (readSTRef r)
y = runST' (writeSTRef r 1 >> return 0)
return (x, y))
-}
-- translation
bad :: ST s (Int, Int)
bad = do r <- newSTRef 0
let x = runST (unsafeCoerce $ readSTRef r)
y = runST (unsafeCoerce $ writeSTRef r 1 >> return 0)
return (x, y)
main = let (x1, y1) = runST bad
(x2, y2) = runST bad
in do print x1
print y1
print y2
print x2