Using Haskell Rank 2 types to contain values

or "How to implement the semantics of the ST monad"

ST lets you create a type of mutable variable, an STRef. This STRef is only valid in the context that it was created. Rank2Types (or RankNTypes) is used to ensure that you can't get an STRef out and access it elsewhere, thus making the function semantically pure and free of side effects

What happens in the ST monad, stays in the ST monad.

How can one write such functions or monads?

Here is an example of using rank 2 types to prevent a type Cat from escaping its context Bag:

{-# LANGUAGE Rank2Types #-} 
import Control.Monad

-- Type trickery to keep the cat in the bag
data Bag s a = Bag a -- like ST
data Cat s a = Cat a -- like STRef

instance Monad (Bag s) where
    (>>== bindBag
    return = returnBag

runBag :: forall a. (forall s. Bag s a) -> a
runBag k = case k of Bag a -> a

newCat :: a -> (forall s. Bag s (Cat s a))
newCat x = Bag (Cat x)

readCat :: forall s. forall a. (Cat s a -> Bag s a)
readCat x = case x of (Cat v) -> Bag v

bindBag :: Bag s a -> (a -> Bag s b) -> Bag s b
bindBag s f = case s of Bag x -> f x

returnBag :: a -> forall s. Bag s a 
returnBag x = Bag x

-- Works, cat stays in the bag
test = runBag $ do
    cat <- newCat "meow"
    value <- readCat cat
    return value

-- --Doesn't compile - attempts to let the cat out
-- fail = runBag $ do
--     cat <- newCat "meow"
--     return cat