diff --git a/Control/Monad/Primitive.hs b/Control/Monad/Primitive.hs
--- a/Control/Monad/Primitive.hs
+++ b/Control/Monad/Primitive.hs
@@ -11,9 +11,14 @@
 -- Primitive state-transformer monads
 --
 
-module Control.Monad.Primitive ( PrimMonad(..), primitive_ ) where
+module Control.Monad.Primitive (
+  PrimMonad(..), RealWorld, primitive_,
+  primToPrim, primToIO, primToST,
+  unsafePrimToPrim, unsafePrimToIO, unsafePrimToST
+) where
 
 import GHC.Prim   ( State#, RealWorld )
+import GHC.Base   ( unsafeCoerce# )
 import GHC.IOBase ( IO(..) )
 import GHC.ST     ( ST(..) )
 
@@ -25,6 +30,10 @@
   -- | Execute a primitive operation
   primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
 
+
+  -- | Expose the internal structure of the monad
+  internal :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)
+
 -- | Execute a primitive operation with no result
 primitive_ :: PrimMonad m
               => (State# (PrimState m) -> State# (PrimState m)) -> m ()
@@ -34,8 +43,37 @@
 instance PrimMonad IO where
   type PrimState IO = RealWorld
   primitive = IO
+  internal (IO p) = p
 
 instance PrimMonad (ST s) where
   type PrimState (ST s) = s
   primitive = ST
+  internal (ST p) = p
+
+-- | Convert a 'PrimMonad' to another monad with the same state token.
+primToPrim :: (PrimMonad m1, PrimMonad m2, PrimState m1 ~ PrimState m2)
+        => m1 a -> m2 a
+primToPrim m = primitive (internal m)
+
+-- | Convert a 'PrimMonad' with a 'RealWorld' state token to 'IO'
+primToIO :: (PrimMonad m, PrimState m ~ RealWorld) => m a -> IO a
+primToIO = primToPrim
+
+-- | Convert a 'PrimMonad' to 'ST'
+primToST :: PrimMonad m => m a -> ST (PrimState m) a
+primToST = primToPrim
+
+-- | Convert a 'PrimMonad' to another monad with a possibly different state
+-- token. This operation is highly unsafe!
+unsafePrimToPrim :: (PrimMonad m1, PrimMonad m2) => m1 a -> m2 a
+unsafePrimToPrim m = primitive (unsafeCoerce# (internal m))
+
+-- | Convert any 'PrimMonad' to 'ST' with an arbitrary state token. This
+-- operations is highly unsafe!
+unsafePrimToST :: PrimMonad m => m a -> ST s a
+unsafePrimToST = unsafePrimToPrim
+
+-- | Convert any 'PrimMonad' to 'IO'. This operation is highly unsafe!
+unsafePrimToIO :: PrimMonad m => m a -> IO a
+unsafePrimToIO = unsafePrimToPrim
 
diff --git a/Data/Primitive/Array.hs b/Data/Primitive/Array.hs
--- a/Data/Primitive/Array.hs
+++ b/Data/Primitive/Array.hs
@@ -27,23 +27,23 @@
 data Array a = Array (Array# a)
 
 -- | Mutable boxed arrays associated with a primitive state token.
-data MutableArray m a = MutableArray (MutableArray# (PrimState m) a)
+data MutableArray s a = MutableArray (MutableArray# s a)
 
 -- | Create a new mutable array of the specified size and initialise all
 -- elements with the given value.
-newArray :: PrimMonad m => Int -> a -> m (MutableArray m a)
+newArray :: PrimMonad m => Int -> a -> m (MutableArray (PrimState m) a)
 {-# INLINE newArray #-}
 newArray (I# n#) x = primitive
    (\s# -> case newArray# n# x s# of
              (# s'#, arr# #) -> (# s'#, MutableArray arr# #))
 
 -- | Read a value from the array at the given index.
-readArray :: PrimMonad m => MutableArray m a -> Int -> m a
+readArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> m a
 {-# INLINE readArray #-}
 readArray (MutableArray arr#) (I# i#) = primitive (readArray# arr# i#)
 
 -- | Write a value to the array at the given index.
-writeArray :: PrimMonad m => MutableArray m a -> Int -> a -> m ()
+writeArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> a -> m ()
 {-# INLINE writeArray #-}
 writeArray (MutableArray arr#) (I# i#) x = primitive_ (writeArray# arr# i# x)
 
@@ -82,7 +82,7 @@
 
 -- | Convert a mutable array to an immutable one without copying. The
 -- array should not be modified after the conversion.
-unsafeFreezeArray :: PrimMonad m => MutableArray m a -> m (Array a)
+unsafeFreezeArray :: PrimMonad m => MutableArray (PrimState m) a -> m (Array a)
 {-# INLINE unsafeFreezeArray #-}
 unsafeFreezeArray (MutableArray arr#)
   = primitive (\s# -> case unsafeFreezeArray# arr# s# of
@@ -90,7 +90,7 @@
 
 -- | Convert an immutable array to an mutable one without copying. The
 -- immutable array should not be used after the conversion.
-unsafeThawArray :: PrimMonad m => Array a -> m (MutableArray m a)
+unsafeThawArray :: PrimMonad m => Array a -> m (MutableArray (PrimState m) a)
 {-# INLINE unsafeThawArray #-}
 unsafeThawArray (Array arr#)
   = primitive (\s# -> case unsafeThawArray# arr# s# of
diff --git a/Data/Primitive/ByteArray.hs b/Data/Primitive/ByteArray.hs
--- a/Data/Primitive/ByteArray.hs
+++ b/Data/Primitive/ByteArray.hs
@@ -31,10 +31,10 @@
 data ByteArray = ByteArray ByteArray#
 
 -- | Mutable byte arrays associated with a primitive state token
-data MutableByteArray m = MutableByteArray (MutableByteArray# (PrimState m))
+data MutableByteArray s = MutableByteArray (MutableByteArray# s)
 
 -- | Create a new mutable byte array of the specified size.
-newByteArray :: PrimMonad m => Int -> m (MutableByteArray m)
+newByteArray :: PrimMonad m => Int -> m (MutableByteArray (PrimState m))
 {-# INLINE newByteArray #-}
 newByteArray (I# n#)
   = primitive (\s# -> case newByteArray# n# s# of
@@ -42,7 +42,7 @@
 
 -- | Create a /pinned/ byte array of the specified size. The garbage collector
 -- is guaranteed not to move it.
-newPinnedByteArray :: PrimMonad m => Int -> m (MutableByteArray m)
+newPinnedByteArray :: PrimMonad m => Int -> m (MutableByteArray (PrimState m))
 {-# INLINE newPinnedByteArray #-}
 newPinnedByteArray (I# n#)
   = primitive (\s# -> case newPinnedByteArray# n# s# of
@@ -50,7 +50,8 @@
 
 -- | Create a /pinned/ byte array of the specified size and with the give
 -- alignment. The garbage collector is guaranteed not to move it.
-newAlignedPinnedByteArray :: PrimMonad m => Int -> Int -> m (MutableByteArray m)
+newAlignedPinnedByteArray
+  :: PrimMonad m => Int -> Int -> m (MutableByteArray (PrimState m))
 {-# INLINE newAlignedPinnedByteArray #-}
 newAlignedPinnedByteArray (I# n#) (I# k#)
   = primitive (\s# -> case newAlignedPinnedByteArray# n# k# s# of
@@ -71,7 +72,8 @@
 
 -- | Convert a mutable byte array to an immutable one without copying. The
 -- array should not be modified after the conversion.
-unsafeFreezeByteArray :: PrimMonad m => MutableByteArray m -> m ByteArray
+unsafeFreezeByteArray
+  :: PrimMonad m => MutableByteArray (PrimState m) -> m ByteArray
 {-# INLINE unsafeFreezeByteArray #-}
 unsafeFreezeByteArray (MutableByteArray arr#)
   = primitive (\s# -> case unsafeFreezeByteArray# arr# s# of
@@ -95,7 +97,8 @@
 
 -- | Read a primitive value from the byte array. The offset is given in
 -- elements of type @a@ rather than in bytes.
-readByteArray :: (Prim a, PrimMonad m) => MutableByteArray m -> Int -> m a
+readByteArray
+  :: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -> Int -> m a
 {-# INLINE readByteArray #-}
 readByteArray (MutableByteArray arr#) (I# i#)
   = primitive (readByteArray# arr# i#)
@@ -103,7 +106,7 @@
 -- | Write a primitive value to the byte array. The offset is given in
 -- elements of type @a@ rather than in bytes.
 writeByteArray
-  :: (Prim a, PrimMonad m) => MutableByteArray m -> Int -> a -> m ()
+  :: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -> Int -> a -> m ()
 {-# INLINE writeByteArray #-}
 writeByteArray (MutableByteArray arr#) (I# i#) x
   = primitive_ (writeByteArray# arr# i# x)
diff --git a/primitive.cabal b/primitive.cabal
--- a/primitive.cabal
+++ b/primitive.cabal
@@ -1,10 +1,11 @@
 Name:           primitive
-Version:        0.1
+Version:        0.2
 License:        BSD3
 License-File:   LICENSE
 Author:         Roman Leshchinskiy <rl@cse.unsw.edu.au>
 Maintainer:     Roman Leshchinskiy <rl@cse.unsw.edu.au>
 Copyright:      (c) Roman Leshchinskiy 2009
+Homepage:       http://www.cse.unsw.edu.au/~rl/darcs/primitive
 Category:       Data
 Synopsis:       Wrappers for primitive operations
 Description:
