s stores objects inside the ST monad from leakage outside the ST monad.
Well, this is a type error (that's good, we donβt want STRef leak out of the original calculations!). This is a type error due to extra s . Remember that runST has a signature:
runST :: (forall s . ST sa) -> a
This means that in s there should be no restrictions on the calculation you performed. Therefore, when you try to evaluate a :
a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))
The result will be of type STRef s Int , which is incorrect, since s "escaped" outside of forall in runST . Type variables should always appear inside forall , and Haskell allows implicit forall quantifiers everywhere. There simply is no rule to significantly interpret the return type of a .
Another example with forall : To clearly show why you cannot let things escape forall , here is a simpler example:
f :: (forall a. [a] -> b) -> Bool -> b fg flag = if flag then g "abcd" else g [1,2] > :tf length f length :: Bool -> Int > :tf id -- error --
Of course, f id is an error, as it will return either a Char list or an Int list, depending on whether the boolean value is true or false. This is simply wrong, as in the example with ST .
On the other hand, if you did not have a parameter of type s , then everything will gain verification just fine, although the code is clearly quite fictitious.
How ST works: Implementation, the ST monad is actually the same as the IO monad, but with a slightly different interface. When you use the ST monad, you actually get unsafePerformIO or the equivalent behind the scenes. The reason you can do it safely is a signature like all ST related functions, especially the part with forall .