diff --git a/Concurrential.cabal b/Concurrential.cabal
--- a/Concurrential.cabal
+++ b/Concurrential.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                Concurrential
-version:             0.4.0.0
+version:             0.5.0.0
 synopsis:            Mix concurrent and sequential computation
 -- description:         
 homepage:            http://github.com/avieth/Concurrential
diff --git a/Control/Concurrent/Concurrential.hs b/Control/Concurrent/Concurrential.hs
--- a/Control/Concurrent/Concurrential.hs
+++ b/Control/Concurrent/Concurrential.hs
@@ -8,15 +8,19 @@
 Portability : non-portable (GHC only)
 
 The functions @sequentially@ and @concurrently@ inject @IO@ terms into the
-@Concurrential@ monad. This monad's Applicative instance will exploit as
-much concurrency as possible, much like the @Concurrently@ monad from async,
-such that all @sequentially@ terms will be run in the order in which they
-would have been run had they been typical IOs.
+@ConcurrentialAp@ applicative functor, whose applicative instance will exploit
+as much concurrency as possible such that all @sequentially@ terms will be run
+in the order in which they would have been run had they been typical IOs.
+
+Terms of @ConcurrentialAp@ can be transformed into terms of @Concurrential@,
+which is a monad. The order of sequential terms is respected even through
+binds; a sequential term will not be evaluted until all binds appearing
+syntactically earlier than it have been expanded.
 -}
 
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE AutoDeriveTypeable #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -24,15 +28,13 @@
 module Control.Concurrent.Concurrential (
 
     Concurrential
-
-  , Runner
-  , Joiner
+  , ConcurrentialAp(ConcurrentialAp)
 
   , runConcurrential
-  , runConcurrentialSimple
 
   , sequentially
   , concurrently
+  , concurrentially
 
   , wait
 
@@ -42,12 +44,12 @@
 import Control.Monad
 import Control.Concurrent.MVar
 import Control.Concurrent.Async hiding (concurrently)
-import Control.Exception
-import Data.Typeable
 
+-- | An Async without a type parameter, which can be waited for.
 data SomeAsync where
   SomeAsync :: Async a -> SomeAsync
 
+-- | Wait for a SomeAsync to complete.
 waitSomeAsync :: SomeAsync -> IO ()
 waitSomeAsync (SomeAsync async) = wait async >> return ()
 
@@ -68,7 +70,6 @@
 -- | Description of the way in which a monadic term's evaluation should be
 --   carried out.
 data Choice m t = Sequential (m t) | Concurrent (m t)
-  deriving (Typeable)
 
 instance Functor m => Functor (Choice m) where
   fmap f choice = case choice of
@@ -77,86 +78,65 @@
 
 -- | Description of computation which is composed of sequential and concurrent
 --   parts in some monad @m@.
-data Concurrential m t where
-    SCAtom :: Choice m t -> Concurrential m t
-    SCBind :: Concurrential m s -> (s -> Concurrential m t) -> Concurrential m t
-    SCAp :: Concurrential m (r -> t) -> Concurrential m r -> Concurrential m t
-  deriving (Typeable)
+data Concurrential t where
+    SCAtom :: Choice IO t -> Concurrential t
+    SCBind :: Concurrential s -> (s -> Concurrential t) -> Concurrential t
+    SCAp :: Concurrential (r -> t) -> Concurrential r -> Concurrential t
 
-instance Functor m => Functor (Concurrential m) where
+instance Functor Concurrential where
   fmap f sc = case sc of
     SCAtom choice -> SCAtom $ fmap f choice
     SCBind sc k -> SCBind sc ((fmap . fmap) f k)
     SCAp sf sx -> SCAp ((fmap . fmap) f sf) sx
 
-instance Applicative m => Applicative (Concurrential m) where
+instance Applicative Concurrential where
   pure = SCAtom . Sequential . pure
-  (<*>) = SCAp
+  cf <*> cx = SCBind cf (\f -> SCBind cx (\x -> pure (f x)))
 
-instance Applicative m => Monad (Concurrential m) where
+instance Monad Concurrential where
   return = pure
   (>>=) = SCBind
 
--- | This corresponds to the notion of a common type of monad transformer:
---   there is some monad g, and then its associated transformer type f, for
---   instance MaybeT = f and Maybe = g
---   If we have an
---   
---     @
---       f m a
---     @
---
---   then we can get an
---
---     @
---       m (g a)
---     @
---
---   Here we're interested in the special case where we can achieve IO (g a).
---   This does not mean we have to be dealing with an f IO a, it could mean
---   that the IO is buried deeper in the transformer stack!
---
---   Motivation: @Async@ functions work with @IO@ and only @IO@, but the @m@
---   parameter of a Concurrential may be some other monad which is capable of
---   performing @IO@, like @Either String IO@ for instance. In order to run
---   computations in this moand through @Async@, we need to know how to get a
---   hold of an @IO@. That's what the runner does.
-type Runner f g = forall a . f a -> IO (g a)
+-- | Concurrential without a Monad instance, but an Applicative instance
+--   which exploits concurrency.
+newtype ConcurrentialAp t = ConcurrentialAp {
+    unConcurrentialAp :: Concurrential t
+  }
 
--- | A witness of this type proves that g is in some sense compatible with IO:
---   we can bind through it.
-type Joiner g = forall a . g (IO a) -> IO (g a)
+instance Functor ConcurrentialAp where
+  fmap f sc = ConcurrentialAp $ fmap f (unConcurrentialAp sc)
 
+instance Applicative ConcurrentialAp where
+  pure = ConcurrentialAp . pure
+  cf <*> cx = ConcurrentialAp $ SCAp (unConcurrentialAp cf) (unConcurrentialAp cx)
+
 -- | Run a Concurrential term with a continuation. We choose CPS here because
 --   it allows us to explot @withAsync@, giving us a guarantee that an
 --   exception in a spawning thread will kill spawned threads.
 runConcurrentialK
-  :: (Functor f, Applicative f, Monad f)
-  => Joiner f
-  -> Runner m f
-  -> Concurrential m t
+  :: Concurrential t
   -- ^ The computation to run.
   -> SomeAsync
   -- ^ The sequential part.
-  -> ((SomeAsync, Async (f t)) -> IO (f r))
+  -> ((SomeAsync, Async t) -> IO r)
   -- ^ The continuation; fst is sequential part, snd is value part.
-  -> IO (f r)
-runConcurrentialK joiner runner sc sequentialPart k = case sc of
+  -> IO r
+runConcurrentialK cc sequentialPart k = case cc of
     SCAtom choice -> case choice of
         -- The async created becomes the sequential part and the value
         -- part. So when another Sequential is encountered, its value part
         -- will have to wait for this computation to complete.
         Sequential em -> withAsync
-                         (waitSomeAsync sequentialPart >> runner em)
+                         (waitSomeAsync sequentialPart >> em)
                          (\async -> k (SomeAsync async, async))
         -- The async created is the value part, but the sequential part
         -- remains the same.
         Concurrent em -> withAsync
-                         (runner em)
+                         (em)
                          (\async -> k (sequentialPart, async))
 
     SCBind sc next ->
-        runConcurrentialK joiner runner sc sequentialPart $ \(sequentialPart, asyncS) -> do
+        runConcurrentialK sc sequentialPart $ \(sequentialPart, asyncS) -> do
         synchronizeSequentialPart <- newEmptyMVar
         let waitAndContinue = do
                 s <- wait asyncS
@@ -165,13 +145,10 @@
                         wait valuePart
                 let continue = \x ->
                         runConcurrentialK
-                        joiner
-                        runner
                         (next x)
                         sequentialPart
                         synchronizeAndWait
-                let unretracted = fmap continue s
-                fmap join (joiner unretracted)
+                continue s
         -- This is a very sensitive part of the definition. We fire off a thread
         -- to wait for @asyncS@ and then continue through @next@, but we also
         -- create a thread which blocks until the aforementioned has determined
@@ -185,44 +162,27 @@
             k (SomeAsync sequentialPart, async)
 
     SCAp left right ->
-        runConcurrentialK joiner runner left sequentialPart $ \(sequentialPart, asyncF) ->
-        runConcurrentialK joiner runner right sequentialPart $ \(sequentialPart, asyncX) ->
+        runConcurrentialK left sequentialPart $ \(sequentialPart, asyncF) ->
+        runConcurrentialK right sequentialPart $ \(sequentialPart, asyncX) ->
         let waitAndApply = do
                 f <- wait asyncF
                 x <- wait asyncX
-                return $ f <*> x
+                return $ f x
         in  withAsync waitAndApply (\async -> k (sequentialPart, async))
 
--- | Run a Concurrential term, realizing the effects of the IO-like terms which
+-- | Run a Concurrential term, realizing the effects of the IO terms which
 --   compose it.
 runConcurrential
-  :: (Functor f, Applicative f, Monad f)
-  => Joiner f
-  -> Runner m f
-  -> Concurrential m t
-  -> (Async (f t) -> IO (f r))
+  :: Concurrential t
+  -> (Async t -> IO r)
   -- ^ Similar contract to withAsync; the Async argument is useless outside of
   -- this function.
-  -> IO (f r)
-runConcurrential joiner runner c k = do
+  -> IO r
+runConcurrential cc k = do
     let action = \sequentialPart ->
-            runConcurrentialK joiner runner c (SomeAsync sequentialPart) (k . snd)
+            runConcurrentialK cc (SomeAsync sequentialPart) (k . snd)
     withAsync (return ()) action
 
-runConcurrentialSimple :: Concurrential IO t -> (Async t -> IO r) -> IO r
-runConcurrentialSimple c k = runIdentity <$> runConcurrential simpleJoiner simpleRunner c (continue k)
-
-  where
-
-    continue :: (Async t -> IO r) -> (Async (Identity t) -> IO (Identity r))
-    continue k = \async -> Identity <$> k (fmap runIdentity async)
-
-    simpleJoiner :: Joiner Identity
-    simpleJoiner = fmap Identity . runIdentity
-
-    simpleRunner :: Runner IO Identity
-    simpleRunner = fmap Identity
-
 -- | Create an effect which must be run sequentially.
 --   If a @sequentially io@ appears in a @Concurrential t@ term then it will
 --   always be run to completion before any later sequential part of the term
@@ -241,9 +201,8 @@
 --   important point: @concurrently otherIo@ may be run before, during or after
 --   @sequentially io@! The ordering through applicative combinators is
 --   guaranteed only among sequential terms.
---
-sequentially :: m t -> Concurrential m t
-sequentially = SCAtom . Sequential
+sequentially :: IO t -> ConcurrentialAp t
+sequentially = ConcurrentialAp . SCAtom . Sequential
 
 -- | Create an effect which is run concurrently where possible, i.e. whenever it
 --   combined applicatively with other terms. For instance:
@@ -256,5 +215,10 @@
 --   When running the term @a@, the IO term @io@ will be run concurrently with
 --   @someConcurrential@, but not so in @b@, because monadic composition has
 --   been used.
-concurrently :: m t -> Concurrential m t
-concurrently = SCAtom . Concurrent
+concurrently :: IO t -> ConcurrentialAp t
+concurrently = ConcurrentialAp . SCAtom . Concurrent
+
+-- | Inject a ConcurrentialAp into Concurrential, losing the
+--   concurrency-enabling Applicative instance but gaining a Monad instance.
+concurrentially :: ConcurrentialAp t -> Concurrential t
+concurrentially = unConcurrentialAp
