diff --git a/crypto-random-effect.cabal b/crypto-random-effect.cabal
--- a/crypto-random-effect.cabal
+++ b/crypto-random-effect.cabal
@@ -2,7 +2,7 @@
 --  documentation, see http://haskell.org/cabal/users-guide/
 
 name:                crypto-random-effect
-version:             0.1.1
+version:             0.2.0
 synopsis:            A random effect using crypto-random
 description:         Any help (especially documentation) is welcome
 homepage:            https://github.com/ibotty/crypto-random-effect
diff --git a/src/Crypto/Random/Effect.hs b/src/Crypto/Random/Effect.hs
--- a/src/Crypto/Random/Effect.hs
+++ b/src/Crypto/Random/Effect.hs
@@ -1,16 +1,17 @@
+-- | An effect that can generate random bytes.
+--
+-- It is essentially a 'State' monad with a given 'CPRG'.
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TypeOperators #-}
--- | A Random effect.
---
--- Any ideas to let the user specify the random number generator ('C.CPRG')
--- instead of hardcoding 'C.SystemRNG' without complicating the api and
--- reinventing state as 'SetMember' is very welcome.
 module Crypto.Random.Effect
-  ( RNG()
-  , runRNG
+  ( RNG
+  , runSystemRNG
   , runRNGWithPool
+  , runRNG
   , withRNG
   , withRNGIO
   , rngFork
@@ -20,10 +21,10 @@
   , createEntropyPool
   , grabEntropy
   , unsafeGrabEntropy
-  -- | reexports from 'crypto-random'
-  , C.CPRG()
-  , C.SystemRNG()
-  , C.EntropyPool()
+  -- * Re-exports
+  , CPRG()
+  , SystemRNG()
+  , EntropyPool()
   ) where
 
 import Control.Eff
@@ -33,58 +34,94 @@
 import Data.ByteString (ByteString)
 import Data.SecureMem (SecureMem)
 import Data.Typeable (Typeable)
+import Crypto.Random (CPRG, EntropyPool, SystemRNG)
 import qualified Crypto.Random as C
 
-type RNG = State C.SystemRNG
+-- | Type marker to ensure that there is only one RNG.
+data RNG
 
-deriving instance Typeable C.SystemRNG
-deriving instance Typeable C.EntropyPool
+instance SetMember RNG (State gen) (State gen :> a)
 
--- | Run the effect.
-runRNG
+deriving instance Typeable SystemRNG
+deriving instance Typeable EntropyPool
+
+-- | Run the effect using 'SystemRNG'.
+runSystemRNG
   :: SetMember Lift (Lift IO) r
-  => Eff (RNG :> Reader C.EntropyPool :> r) a -> Eff r a
-runRNG e = lift C.createEntropyPool >>= flip runRNGWithPool e
+  => Eff (State SystemRNG :> Reader EntropyPool :> r) a -> Eff r a
+runSystemRNG = runRNG
 
+-- | Run the effect without specifying the 'CPRG'.
+--
+-- This is only useful when the type of the 'CPRG' is bound by an explicit
+-- type annotation (see 'runSystemRNG' which is 'runRNG' with bound type)
+-- or any function within the effect binds it.
+runRNG :: (SetMember Lift (Lift IO) r, Typeable gen, CPRG gen)
+  => Eff (State gen :> Reader EntropyPool :> r) a -> Eff r a
+runRNG e = createEntropyPool >>= flip runRNGWithPool e
+
+-- | Run the effect with a given 'EntropyPool'.
 runRNGWithPool
-  :: SetMember Lift (Lift IO) r
-  => C.EntropyPool -> Eff (RNG :> Reader C.EntropyPool :> r) a -> Eff r a
+  :: (SetMember Lift (Lift IO) r, Typeable gen, CPRG gen)
+  => EntropyPool -> Eff (State gen :> Reader EntropyPool :> r) a -> Eff r a
 runRNGWithPool pool = flip runReader pool . evalState (C.cprgCreate pool)
 
-withRNG :: Member RNG r => (C.SystemRNG -> Eff r (a, C.SystemRNG)) -> Eff r a
+-- | Wrap an effect that uses the 'CPRG' directly.
+withRNG :: (SetMember RNG (State gen) r, Typeable gen) => (gen -> Eff r (a, gen)) -> Eff r a
 withRNG f = do
     rng <- get
     (a, rng') <- f rng
     put rng'
     return a
 
-withRNGPure :: Member RNG r => (C.SystemRNG -> (a, C.SystemRNG)) -> Eff r a
+-- | Wrap a pure function that uses the 'CPRG' directly.
+withRNGPure :: (SetMember RNG (State gen) r, Typeable gen) => (gen -> (a, gen)) -> Eff r a
 withRNGPure f = withRNG (return . f)
 
+-- | Wrap an IO action that uses the 'CPRG' directly.
 withRNGIO
-  :: (SetMember Lift (Lift IO) r, Member RNG r)
-  => (C.SystemRNG -> IO (a, C.SystemRNG)) -> Eff r a
+  :: (SetMember Lift (Lift IO) r, SetMember RNG (State gen) r, Typeable gen)
+  => (gen -> IO (a, gen)) -> Eff r a
 withRNGIO f = withRNG (lift . f)
 
-rngFork :: Member RNG r => Eff r C.SystemRNG
+-- | Fork a CPRG into a new independent CPRG.
+--
+-- As entropy is mixed to generate safely a new generator, 2 calls with the
+-- same CPRG will not produce the same output.
+rngFork :: (SetMember RNG (State gen) r, CPRG gen, Typeable gen) => Eff r gen
 rngFork = withRNGPure C.cprgFork
 
-randomBytes :: Member RNG r => Int -> Eff r ByteString
+-- | Generate a number of bytes using the CPRG.
+randomBytes :: (SetMember RNG (State gen) r, CPRG gen, Typeable gen) => Int -> Eff r ByteString
 randomBytes = withRNGPure . C.cprgGenerate
 
-randomBytesWithEntropy :: Member RNG r => Int -> Eff r ByteString
+-- | Similar to 'randomBytes' except that the random data is mixed with pure
+-- entropy, so the result is not reproducible after use, but it provides
+-- more guarantee, theorically speaking, in term of the randomness
+-- generated.
+randomBytesWithEntropy :: (SetMember RNG (State gen) r, CPRG gen, Typeable gen) => Int -> Eff r ByteString
 randomBytesWithEntropy = withRNGPure . C.cprgGenerateWithEntropy
 
-withRandomBytes :: Member RNG r => Int -> (ByteString -> Eff r a) -> Eff r a
-withRandomBytes cnt f = randomBytes cnt >>= f
+-- | Consume a number of random bytes with a pure function.
+--
+-- Note, that this is simply
+--
+-- > randomBytes cnt >>= return . f
+withRandomBytes :: (SetMember RNG (State gen) r, CPRG gen, Typeable gen) => Int -> (ByteString -> a) -> Eff r a
+withRandomBytes cnt f = randomBytes cnt >>= return . f
 
-createEntropyPool :: SetMember Lift (Lift IO) r => Eff r C.EntropyPool
+-- Create a new entropy pool.
+createEntropyPool :: SetMember Lift (Lift IO) r => Eff r EntropyPool
 createEntropyPool = lift C.createEntropyPool
 
+-- | Grab a chunk of entropy from the entropy pool.
 grabEntropy
-  :: (SetMember Lift (Lift IO) r, Member (Reader C.EntropyPool) r)
+  :: (SetMember Lift (Lift IO) r, Member (Reader EntropyPool) r)
   => Int -> Eff r SecureMem
 grabEntropy cnt = ask >>= lift . C.grabEntropyIO cnt
 
-unsafeGrabEntropy :: Member (Reader C.EntropyPool) r => Int -> Eff r SecureMem
+-- | Grab a chunk of entropy from the entropy pool.
+--
+-- Beware: uses unsafePerformIO under the hood.
+unsafeGrabEntropy :: Member (Reader EntropyPool) r => Int -> Eff r SecureMem
 unsafeGrabEntropy cnt = fmap (C.grabEntropy cnt) ask
