
-- 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

