diff --git a/extensible-effects.cabal b/extensible-effects.cabal
--- a/extensible-effects.cabal
+++ b/extensible-effects.cabal
@@ -1,11 +1,13 @@
 Name:                extensible-effects
-Version:             1.1.0
+Version:             1.2.0
 Synopsis:            An Alternative to Monad Transformers
 Description:         This package introduces datatypes for typeclass-constrained effects,
                      as an alternative to monad-transformer based (datatype-constrained)
                      approach of multi-layered effects.
                      For more information, see the original paper at
                      <http://okmij.org/ftp/Haskell/extensible/exteff.pdf>.
+
+                     Any help is appreciated!
 Category:            Control
 Author:              Oleg Kiselyov, Amr Sabry, Cameron Swords, Ben Foppa
 Stability:           Experimental
@@ -26,7 +28,12 @@
                        Control.Eff.Exception
                        Control.Eff.Fresh
                        Control.Eff.Lift
-                       Control.Eff.State
+                       Control.Eff.Reader.Lazy
+                       Control.Eff.Reader.Strict
+                       Control.Eff.State.Lazy
+                       Control.Eff.State.Strict
+                       Control.Eff.Writer.Lazy
+                       Control.Eff.Writer.Strict
                        Control.Eff.Trace
     other-modules:     Data.OpenUnion1
 
@@ -43,7 +50,9 @@
   build-depends:
     base == 4.*,
     QuickCheck == 2.*,
+    HUnit == 1.2.*,
     test-framework == 0.8.*,
+    test-framework-hunit == 0.3.*,
     test-framework-quickcheck2 == 0.3.*,
     extensible-effects
 
diff --git a/src/Control/Eff.hs b/src/Control/Eff.hs
--- a/src/Control/Eff.hs
+++ b/src/Control/Eff.hs
@@ -65,6 +65,7 @@
                     Eff
                   , VE (..)
                   , Member
+                  , SetMember
                   , Union
                   , (:>)
                   , inj
diff --git a/src/Control/Eff/Lift.hs b/src/Control/Eff/Lift.hs
--- a/src/Control/Eff/Lift.hs
+++ b/src/Control/Eff/Lift.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
@@ -24,8 +26,10 @@
 instance Functor (Lift m) where
     fmap f (Lift m k) = Lift m (f . k)
 
+instance SetMember Lift (Lift m) (Lift m :> ())
+
 -- | Lift a Monad to an Effect.
-lift :: (Typeable1 m, Member (Lift m) r) => m a -> Eff r a
+lift :: (Typeable1 m, Member (Lift m) r, SetMember Lift (Lift m) r) => m a -> Eff r a
 lift m = send (inj . Lift m)
 
 -- | The handler of Lift requests. It is meant to be terminal:
diff --git a/src/Control/Eff/Reader/Lazy.hs b/src/Control/Eff/Reader/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Eff/Reader/Lazy.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Lazy read-only state
+module Control.Eff.Reader.Lazy( Reader
+                              , ask
+                              , local
+                              , reader
+                              , runReader
+                              ) where
+
+import Control.Applicative ((<$>))
+import Data.Typeable
+
+import Control.Eff
+
+-- | The request for a value of type e from the current environment.
+-- This environment is analogous to a parameter of type e.
+newtype Reader e v = Reader (e -> v)
+    deriving (Typeable, Functor)
+
+-- | Get the current value from a Reader.
+ask :: (Typeable e, Member (Reader e) r) => Eff r e
+ask = send (inj . Reader)
+
+-- | Locally rebind the value in the dynamic environment.
+-- This function both requests and admins Reader requests.
+local :: (Typeable e, Member (Reader e) r)
+      => (e -> e)
+      -> Eff r a
+      -> Eff r a
+local f m = do
+  e <- f <$> ask
+  let loop (Val x) = return x
+      loop (E u) = interpose u loop (\(Reader k) -> loop (k e))
+  loop (admin m)
+
+-- | Request the environment value using a transformation function.
+reader :: (Typeable e, Member (Reader e) r) => (e -> a) -> Eff r a
+reader f = f <$> ask
+
+-- | The handler of Reader requests. The return type shows that
+-- all Reader requests are fully handled.
+runReader :: Typeable e => Eff (Reader e :> r) w -> e -> Eff r w
+runReader m e = loop (admin m)
+  where
+    loop (Val x) = return x
+    loop (E u) = handleRelay u loop (\(Reader k) -> loop (k e))
diff --git a/src/Control/Eff/Reader/Strict.hs b/src/Control/Eff/Reader/Strict.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Eff/Reader/Strict.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Strict read-only state
+module Control.Eff.Reader.Strict( Reader
+                                , ask
+                                , local
+                                , reader
+                                , runReader
+                                ) where
+
+import Control.Applicative ((<$>))
+import Data.Typeable
+
+import Control.Eff
+
+-- | The request for a value of type e from the current environment.
+-- This environment is analogous to a parameter of type e.
+newtype Reader e v = Reader (e -> v)
+    deriving (Typeable, Functor)
+
+-- | Get the current value from a Reader.
+ask :: (Typeable e, Member (Reader e) r) => Eff r e
+ask = send (inj . Reader)
+
+-- | Locally rebind the value in the dynamic environment.
+-- This function both requests and admins Reader requests.
+local :: (Typeable e, Member (Reader e) r)
+      => (e -> e)
+      -> Eff r a
+      -> Eff r a
+local f m = do
+  e <- f <$> ask
+  let loop (Val x) = return x
+      loop (E u) = interpose u loop (\(Reader k) -> loop (k e))
+  loop (admin m)
+
+-- | Request the environment value using a transformation function.
+reader :: (Typeable e, Member (Reader e) r) => (e -> a) -> Eff r a
+reader f = f <$> ask
+
+-- | The handler of Reader requests. The return type shows that
+-- all Reader requests are fully handled.
+runReader :: Typeable e => Eff (Reader e :> r) w -> e -> Eff r w
+runReader m !e = loop (admin m) where
+ loop (Val x) = return x
+ loop (E u) = handleRelay u loop (\(Reader k) -> loop (k e))
diff --git a/src/Control/Eff/State.hs b/src/Control/Eff/State.hs
deleted file mode 100644
--- a/src/Control/Eff/State.hs
+++ /dev/null
@@ -1,123 +0,0 @@
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
--- | Strict state effect
---
--- Example: implementing `Control.Eff.Fresh`
---
--- > runFresh' :: (Typeable i, Enum i, Num i) => Eff (Fresh i :> r) w -> i -> Eff r w
--- > runFresh' m s = fst <$> runState s (loop $ admin m)
--- >  where
--- >   loop (Val x) = return x
--- >   loop (E u)   = case decomp u of
--- >     Right (Fresh k) -> do
--- >                       n <- getState
--- >                       putState (n + 1)
--- >                       loop (k n)
--- >     Left u' -> send (\k -> unsafeReUnion $ k <$> u') >>= loop
-module Control.Eff.State(
-                        -- * Read-write State
-                          State
-                        , getState
-                        , putState
-                        , onState
-                        , runState
-                        -- * Reader
-                        , Reader
-                        , getReader
-                        , runReader
-                        , local
-                        -- * Writer
-                        , Writer
-                        , putWriter
-                        , runWriter
-                        , runPusher
-                        ) where
-
-import Control.Applicative ((<$>), (<|>))
-import Data.Typeable
-
-import Control.Eff
-
--- | Strict state effect
-data State s w = State (s -> s) (s -> w)
-  deriving (Typeable, Functor)
-
--- | Write a new value of the state.
-putState :: Typeable e => Member (State e) r => e -> Eff r ()
-putState = onState . const
-
--- | Return the current value of the state.
-getState :: Typeable e => Member (State e) r => Eff r e
-getState = send (inj . State id)
-
--- | Transform the state with a function.
-onState :: (Typeable s, Member (State s) r) => (s -> s) -> Eff r ()
-onState f = send (\k -> inj (State f (\_ -> k ())))
-
--- | Run a State effect.
-runState :: Typeable s
-         => s                     -- ^ Initial state
-         -> Eff (State s :> r) w  -- ^ Effect incorporating State
-         -> Eff r (s, w)          -- ^ Effect containing final state and a return value
-runState s0 = loop s0 . admin where
- loop s (Val x) = return (s, x)
- loop s (E u)   = handleRelay u (loop s) $
-                       \(State t k) -> let s' = t s in s' `seq` loop s' (k s')
-
--- ------------------------------------------------------------------------
--- The Reader monad
-
--- | The request for a value of type e from the current environment.
--- This environment is analogous to a parameter of type e.
-newtype Reader e v = Reader (e -> v)
-    deriving (Typeable, Functor)
-
--- | Get the current value from a Reader.
-getReader :: (Typeable e, Member (Reader e) r) => Eff r e
-getReader = send (inj . Reader)
-
--- | The handler of Reader requests. The return type shows that
--- all Reader requests are fully handled.
-runReader :: Typeable e => Eff (Reader e :> r) w -> e -> Eff r w
-runReader m e = loop (admin m) where
- loop (Val x) = return x
- loop (E u) = handleRelay u loop (\(Reader k) -> loop (k e))
-
--- | Locally rebind the value in the dynamic environment.
--- This function both requests and admins Reader requests.
-local :: (Typeable e, Member (Reader e) r) =>
-     (e -> e) -> Eff r a -> Eff r a
-local f m = do
-  e <- f <$> getReader
-  let loop (Val x) = return x
-      loop (E u) = interpose u loop (\(Reader k) -> loop (k e))
-  loop (admin m)
-
--- ------------------------------------------------------------------------
--- | The request to remember a value of type e in the current environment
-data Writer e v = Writer e v
-    deriving (Typeable, Functor)
-
-putWriter :: (Typeable e, Member (Writer e) r) => e -> Eff r ()
-putWriter e = send $ \f -> inj $ Writer e $ f ()
-
--- | Handle Writer requests by overwriting previous values.
--- If no value of type @e@ was returned, Nothing is returned;
--- otherwise return Just the most recent value written.
-runWriter :: Typeable e => Eff (Writer e :> r) w -> Eff r (Maybe e, w)
-runWriter = loop . admin
-  where
-    correctVal f = fmap $ \(x, y) -> (f x, y)
-
-    loop (Val x) = return (Nothing, x)
-    loop (E u) = handleRelay u loop (\(Writer e v) -> correctVal (<|> Just e) $ loop v)
-
--- | Handle Writer requests by stacking written values on to a list.
-runPusher :: Typeable e => Eff (Writer e :> r) w -> Eff r ([e], w)
-runPusher = loop . admin
-  where
-    loop (Val x) = return ([], x)
-    loop (E u) = handleRelay u loop (\(Writer e v) -> (\(es, v') -> (e:es, v')) <$> loop v)
diff --git a/src/Control/Eff/State/Lazy.hs b/src/Control/Eff/State/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Eff/State/Lazy.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Lazy state effect
+module Control.Eff.State.Lazy( State
+                             , get
+                             , put
+                             , modify
+                             , runState
+                             ) where
+
+import Data.Typeable
+
+import Control.Eff
+
+-- | Strict state effect
+data State s w = State (s -> s) (s -> w)
+  deriving (Typeable, Functor)
+
+-- | Write a new value of the state.
+put :: (Typeable e, Member (State e) r) => e -> Eff r ()
+put = modify . const
+
+-- | Return the current value of the state.
+get :: (Typeable e, Member (State e) r) => Eff r e
+get = send (inj . State id)
+
+-- | Transform the state with a function.
+modify :: (Typeable s, Member (State s) r) => (s -> s) -> Eff r ()
+modify f = send $ \k -> inj $ State f $ \_ -> k ()
+
+-- | Run a State effect.
+runState :: Typeable s
+         => s                     -- ^ Initial state
+         -> Eff (State s :> r) w  -- ^ Effect incorporating State
+         -> Eff r (s, w)          -- ^ Effect containing final state and a return value
+runState s0 = loop s0 . admin where
+ loop s (Val x) = return (s, x)
+ loop s (E u)   = handleRelay u (loop s) $
+                       \(State t k) -> let s' = t s
+                                       in loop s' (k s')
diff --git a/src/Control/Eff/State/Strict.hs b/src/Control/Eff/State/Strict.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Eff/State/Strict.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Strict state effect
+--
+-- Example: implementing `Control.Eff.Fresh`
+--
+-- > runFresh' :: (Typeable i, Enum i, Num i) => Eff (Fresh i :> r) w -> i -> Eff r w
+-- > runFresh' m s = fst <$> runState s (loop $ admin m)
+-- >  where
+-- >   loop (Val x) = return x
+-- >   loop (E u)   = case decomp u of
+-- >     Right (Fresh k) -> do
+-- >                       n <- get
+-- >                       put (n + 1)
+-- >                       loop (k n)
+-- >     Left u' -> send (\k -> unsafeReUnion $ k <$> u') >>= loop
+module Control.Eff.State.Strict( State
+                               , get
+                               , put
+                               , modify
+                               , runState
+                               ) where
+
+import Data.Typeable
+
+import Control.Eff
+
+-- | Strict state effect
+data State s w = State (s -> s) (s -> w)
+  deriving (Typeable, Functor)
+
+-- | Write a new value of the state.
+put :: (Typeable e, Member (State e) r) => e -> Eff r ()
+put !s = modify $ const s
+
+-- | Return the current value of the state.
+get :: (Typeable e, Member (State e) r) => Eff r e
+get = send (inj . State id)
+
+-- | Transform the state with a function.
+modify :: (Typeable s, Member (State s) r) => (s -> s) -> Eff r ()
+modify f = send $ \k -> inj $ State f $ \_ -> k ()
+
+-- | Run a State effect.
+runState :: Typeable s
+         => s                     -- ^ Initial state
+         -> Eff (State s :> r) w  -- ^ Effect incorporating State
+         -> Eff r (s, w)          -- ^ Effect containing final state and a return value
+runState s0 = loop s0 . admin where
+ loop !s (Val x) = return (s, x)
+ loop !s (E u)   = handleRelay u (loop s) $
+                       \(State t k) -> let s' = t s
+                                       in loop s' (k s')
diff --git a/src/Control/Eff/Writer/Lazy.hs b/src/Control/Eff/Writer/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Eff/Writer/Lazy.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Lazy write-only state.
+module Control.Eff.Writer.Lazy( Writer
+                              , tell
+                              , censor
+                              , runWriter
+                              , runFirstWriter
+                              , runLastWriter
+                              , runMonoidWriter
+                              ) where
+
+import Control.Applicative ((<$>), (<|>))
+import Data.Monoid
+import Data.Typeable
+
+import Control.Eff
+
+-- | The request to remember a value of type w in the current environment
+data Writer w v = Writer w v
+    deriving (Typeable, Functor)
+
+-- | Write a new value.
+tell :: (Typeable w, Member (Writer w) r) => w -> Eff r ()
+tell w = send $ \f -> inj $ Writer w $ f ()
+
+-- | Transform the state being produced.
+censor :: (Typeable w, Member (Writer w) r) => (w -> w) -> Eff r a -> Eff r a
+censor f = loop . admin
+  where
+    loop (Val x) = return x
+    loop (E u) = interpose u loop
+               $ \(Writer w v) -> tell (f w) >> loop v
+
+-- | Handle Writer requests, using a user-provided function to accumulate values.
+runWriter :: Typeable w => (w -> b -> b) -> b -> Eff (Writer w :> r) a -> Eff r (b, a)
+runWriter accum b = loop . admin
+  where
+    first f (x, y) = (f x, y)
+
+    loop (Val x) = return (b, x)
+    loop (E u) = handleRelay u loop
+                 $ \(Writer w v) -> first (accum w) <$> loop v
+
+-- | Handle Writer requests by taking the first value provided.
+runFirstWriter :: Typeable w => Eff (Writer w :> r) a -> Eff r (Maybe w, a)
+runFirstWriter = runWriter (\w b -> Just w <|> b) Nothing
+
+-- | Handle Writer requests by overwriting previous values.
+runLastWriter :: Typeable w => Eff (Writer w :> r) a -> Eff r (Maybe w, a)
+runLastWriter = runWriter (\w b -> b <|> Just w) Nothing
+
+-- | Handle Writer requests, using a Monoid instance to accumulate values.
+runMonoidWriter :: (Monoid w, Typeable w) => Eff (Writer w :> r) a -> Eff r (w, a)
+runMonoidWriter = runWriter (<>) mempty
diff --git a/src/Control/Eff/Writer/Strict.hs b/src/Control/Eff/Writer/Strict.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Eff/Writer/Strict.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Strict write-only state.
+module Control.Eff.Writer.Strict( Writer
+                                , tell
+                                , censor
+                                , runWriter
+                                , runFirstWriter
+                                , runLastWriter
+                                , runMonoidWriter
+                                ) where
+
+import Control.Applicative ((<$>), (<|>))
+import Data.Monoid
+import Data.Typeable
+
+import Control.Eff
+
+-- | The request to remember a value of type w in the current environment
+data Writer w v = Writer !w v
+    deriving (Typeable, Functor)
+
+-- | Write a new value.
+tell :: (Typeable w, Member (Writer w) r) => w -> Eff r ()
+tell !w = send $ \f -> inj $ Writer w $ f ()
+
+-- | Transform the state being produced.
+censor :: (Typeable w, Member (Writer w) r) => (w -> w) -> Eff r a -> Eff r a
+censor f = loop . admin
+  where
+    loop (Val x) = return x
+    loop (E u) = interpose u loop
+               $ \(Writer w v) -> tell (f w) >> loop v
+
+-- | Handle Writer requests, using a user-provided function to accumulate values.
+runWriter :: Typeable w => (w -> b -> b) -> b -> Eff (Writer w :> r) a -> Eff r (b, a)
+runWriter accum !b = loop . admin
+  where
+    first f (x, y) = (f x, y)
+
+    loop (Val x) = return (b, x)
+    loop (E u) = handleRelay u loop
+                 $ \(Writer w v) -> first (accum w) <$> loop v
+
+-- | Handle Writer requests by taking the first value provided.
+runFirstWriter :: Typeable w => Eff (Writer w :> r) a -> Eff r (Maybe w, a)
+runFirstWriter = runWriter (\w b -> Just w <|> b) Nothing
+
+-- | Handle Writer requests by overwriting previous values.
+runLastWriter :: Typeable w => Eff (Writer w :> r) a -> Eff r (Maybe w, a)
+runLastWriter = runWriter (\w b -> b <|> Just w) Nothing
+
+-- | Handle Writer requests, using a Monoid instance to accumulate values.
+runMonoidWriter :: (Monoid w, Typeable w) => Eff (Writer w :> r) a -> Eff r (w, a)
+runMonoidWriter = runWriter (<>) mempty
diff --git a/src/Data/OpenUnion1.hs b/src/Data/OpenUnion1.hs
--- a/src/Data/OpenUnion1.hs
+++ b/src/Data/OpenUnion1.hs
@@ -2,6 +2,8 @@
 {-# LANGUAGE EmptyDataDecls #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
 {-# LANGUAGE OverlappingInstances #-}
 {-# LANGUAGE UndecidableInstances #-}
@@ -11,12 +13,13 @@
 -- This implementation relies on _closed_ overlapping instances
 -- (or closed type function overlapping soon to be added to GHC).
 module Data.OpenUnion1( Union
+                      , SetMember
+                      , Member
                       , (:>)
                       , inj
                       , prj
                       , prjForce
                       , decomp
-                      , Member
                       , unsafeReUnion
                       ) where
 
@@ -46,11 +49,26 @@
 infixr 1 :>
 data ((a :: * -> *) :> b)
 
--- | There's a @`Member` t r@ instance if t is an element of the sum datatype r.
-class Member (t :: * -> *) r
+-- | The @`Member` t r@ determines whether @t@ is anywhere in the sum type @r@.
+class Member t r
 instance Member t (t :> r)
 instance Member t r => Member t (t' :> r)
 
+-- | `SetMember` is similar to `Member`, but it allows types to belong to a
+-- "set", by taking advantage of the @r set -> t@ fundep:
+--
+-- > -- Terminal effects (effects which must be run last)
+-- > data Terminal
+-- >
+-- > -- Make Lifts part of the Terminal effects set.
+-- > -- The fundep assures that there can only be one Terminal effect for any r.
+-- > instance Member (Lift m) r => SetMember Terminal (Lift m) r
+-- >
+-- > -- Only allow a single unique Lift effect, by making a "Lift" set.
+-- > instance Member (Lift m) r => SetMember Lift (Lift m) r
+class  Member t r => SetMember set (t :: * -> *) r | r set -> t
+instance SetMember set t r => SetMember set t (t' :> r)
+
 {-# INLINE inj #-}
 -- | Construct a Union.
 inj :: (Functor t, Typeable1 t, Member t r) => t v -> Union r v
@@ -70,7 +88,7 @@
 {-# INLINE decomp #-}
 -- | Try extracting the contents of a Union as a given type.
 -- If we can't, return a reduced Union that excludes the type we just checked.
-decomp :: (Typeable1 t, Member t (t :> r)) => Union (t :> r) v -> Either (Union r v) (t v)
+decomp :: Typeable1 t => Union (t :> r) v -> Either (Union r v) (t v)
 decomp u = Right <$> prj u <?> Left (unsafeReUnion u)
 
 {-# INLINE unsafeReUnion #-}
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -1,16 +1,34 @@
+{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE FlexibleContexts #-}
-import Control.Eff
-import Control.Eff.Lift
-import Control.Eff.State
-
+import Control.Exception (Exception, ErrorCall, catch)
 import Control.Monad (void)
 import Data.Typeable
 
 import Test.Framework (defaultMain, testGroup)
+import Test.Framework.Providers.HUnit
 import Test.Framework.Providers.QuickCheck2
 
+import Test.HUnit hiding (State)
 import Test.QuickCheck
 
+import Control.Eff
+import Control.Eff.Lift
+import Control.Eff.Reader.Lazy as LazyR
+import Control.Eff.State.Lazy as LazyS
+import Control.Eff.Writer.Lazy as LazyW
+import Control.Eff.Reader.Strict as StrictR
+import Control.Eff.State.Strict as StrictS
+import Control.Eff.Writer.Strict as StrictW
+
+withError :: a -> ErrorCall -> a
+withError a _ = a
+
+assertUndefined :: a -> Assertion
+assertUndefined a = catch (seq a $ assertFailure "") (withError $ return ())
+
+assertNoUndefined :: a -> Assertion
+assertNoUndefined a = catch (seq a $ return ()) (withError $ assertFailure "")
+
 main :: IO ()
 main = defaultMain tests
 
@@ -24,30 +42,103 @@
 
 testDocs :: [Integer] -> Property
 testDocs l = let
-              (total1, ()) = run $ runState 0 $ sumAll l
-              (last1, ()) = run $ runWriter $ writeAll l
-              (total2, (last2, ())) = run $ runState 0 $ runWriter $ writeAndAdd l
-              (last3, (total3, ())) = run $ runWriter $ runState 0 $ writeAndAdd l
+              (total1, ()) = run $ LazyS.runState 0 $ sumAll l
+              (last1, ()) = run $ LazyW.runLastWriter $ writeAll l
+              (total2, (last2, ())) = run $ LazyS.runState 0 $ LazyW.runLastWriter $ writeAndAdd l
+              (last3, (total3, ())) = run $ LazyW.runLastWriter $ LazyS.runState 0 $ writeAndAdd l
              in allEqual [safeLast l, last1, last2, last3]
            .&&. allEqual [sum l, total1, total2, total3]
   where
-    writeAll :: (Typeable a, Member (Writer a) e)
+    writeAll :: (Typeable a, Member (LazyW.Writer a) e)
              => [a]
              -> Eff e ()
-    writeAll = mapM_ putWriter
+    writeAll = mapM_ LazyW.tell
 
-    sumAll :: (Typeable a, Num a, Member (State a) e)
+    sumAll :: (Typeable a, Num a, Member (LazyS.State a) e)
            => [a]
            -> Eff e ()
-    sumAll = mapM_ (onState . (+))
+    sumAll = mapM_ (LazyS.modify . (+))
     
-    writeAndAdd :: (Member (Writer Integer) e, Member (State Integer) e)
+    writeAndAdd :: (Member (LazyW.Writer Integer) e, Member (LazyS.State Integer) e)
                 => [Integer]
                 -> Eff e ()
     writeAndAdd l = do
         writeAll l
         sumAll l
 
-tests = [
-    testProperty "Documentation example." testDocs
+testCensor :: [Integer] -> Property
+testCensor l = property
+             $ listE (mapM_ (LazyW.tell . inc) l) == listE (LazyW.censor inc $ mapM_ LazyW.tell l)
+  where
+    inc :: Integer -> Integer
+    inc = (+1)
+
+    listE :: Eff (LazyW.Writer Integer :> ()) () -> [Integer]
+    listE = fst . run . LazyW.runWriter (:) []
+
+testReaderLaziness :: Assertion
+testReaderLaziness = let e = run $ LazyR.runReader voidReader (undefined :: ())
+                     in assertNoUndefined (e :: ())
+  where
+    voidReader = do
+        _ <- (LazyR.ask :: Eff (LazyR.Reader () :> ()) ())
+        return ()
+
+testReaderStrictness :: Assertion
+testReaderStrictness = let e = run $ StrictR.runReader voidReader (undefined :: ())
+                       in assertUndefined (e :: ())
+  where
+    voidReader = do
+        _ <- (StrictR.ask :: Eff (StrictR.Reader () :> ()) ())
+        return ()
+
+testStateLaziness :: Assertion
+testStateLaziness = let (r, ()) = run
+                                $ LazyS.runState undefined
+                                $ getVoid
+                               >> putVoid undefined
+                               >> putVoid ()
+                    in assertNoUndefined r
+  where
+    getVoid :: Eff (LazyS.State () :> ()) ()
+    getVoid = LazyS.get
+
+    putVoid :: () -> Eff (LazyS.State () :> ()) ()
+    putVoid = LazyS.put
+
+testStateStrictness :: Assertion
+testStateStrictness = let (r, ()) = run
+                                  $ StrictS.runState undefined
+                                  $ getVoid
+                                 >> putVoid undefined
+                                 >> putVoid ()
+                      in assertUndefined r
+  where
+    getVoid :: Eff (StrictS.State () :> ()) ()
+    getVoid = StrictS.get
+
+    putVoid :: () -> Eff (StrictS.State () :> ()) ()
+    putVoid = StrictS.put
+
+testLastWriterLaziness :: Assertion
+testLastWriterLaziness = let (Just m, ()) = run $ LazyW.runLastWriter $ mapM_ LazyW.tell [undefined, ()]
+                         in assertNoUndefined (m :: ())
+
+testLastWriterStrictness :: Assertion
+testLastWriterStrictness = let (Just m, ()) = run $ StrictW.runLastWriter $ mapM_ StrictW.tell [undefined, ()]
+                           in assertUndefined (m :: ())
+
+testFirstWriterLaziness :: Assertion
+testFirstWriterLaziness = let (Just m, ()) = run $ LazyW.runFirstWriter $ mapM_ LazyW.tell [(), undefined]
+                          in assertNoUndefined (m :: ())
+
+tests =
+  [ testProperty "Documentation example." testDocs
+  , testCase "Test runReader laziness." testReaderLaziness
+  , testCase "Test runReader strictness." testReaderStrictness
+  , testCase "Test runState laziness." testStateLaziness
+  , testCase "Test runState strictness." testStateStrictness
+  , testCase "Test runLastWriter laziness." testLastWriterLaziness
+  , testCase "Test runLastWriter strictness." testLastWriterStrictness
+  , testCase "Test runFirstWriter laziness." testFirstWriterLaziness
   ]
