diff --git a/Control/Concurrent/Actors.lhs b/Control/Concurrent/Actors.lhs
--- a/Control/Concurrent/Actors.lhs
+++ b/Control/Concurrent/Actors.lhs
@@ -1,12 +1,12 @@
-> {-# LANGUAGE CPP, GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}
+> {-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}
 
 This module exports a simple, idiomatic implementation of the Actor Model.
 
 > module Control.Concurrent.Actors (
 >
 >     {- | 
->     Here we demonstrate a binary tree of actors that supports insert and query
->     operations:
+>     Here we demonstrate a binary tree of actors that supports concurrent
+>     insert and query operations:
 >      
 >     > import Control.Concurrent.Actors
 >     > import Control.Applicative
@@ -68,38 +68,15 @@
 >     -}
 >
 >     -- * Actor Behaviors
->     {- | 
->     In the Actor Model, at each step an actor...
->     
->         - processes a single 'received' message
->         
->         - may 'spawn' new actors
->         
->         - may 'send' messages to other actors
->         
->         - 'return's the 'Behavior' for processing the /next/ message
->     
->     These actions take place within the @Action i@ monad, where @i@ is the type
->     of the input message the actor receives.
->     
->     /N.B.:/ the MonadIO instance here is an abstraction leak. An example of a
->     good use of 'liftIO' might be to give an @Action@ access to a source of
->     randomness.
->     -}
 >       Action()
->     {- | 
->     An actor is created by 'spawn'ing a @Behavior@. Behaviors consist of a
->     composed 'Action' that is executed when a message is 'received' and
->     returns the @Behavior@ for processing the next input.
->     -}
 >     , Behavior(..)
->     -- ** Composing Behaviors
+>     -- ** Composing and Transforming Behaviors
 >     , (<.|>)
 >
 >     -- * Available actions
 >     -- ** Message passing
 >     , Mailbox()
->     , send
+>     , send , send' , (<->)
 >     , received
 >     , guardReceived
 >     -- ** Spawning actors
@@ -153,6 +130,17 @@
 >     , yield
 >     , receive
 >
+>     -- ** Composing and Transforming Mailboxes
+>     {- |
+>     We offer some operations to split and combine 'Mailbox'es of sum and
+>     product types. 
+>     -}
+>     , coproductMb
+>     , productMb
+>     , zipMb
+>     , faninMb
+>     , fanoutMb
+>
 >     -- * Utility functions
 >     {- | 
 >     These are useful for debugging 'Behavior's
@@ -174,6 +162,7 @@
 > import Control.Monad.IO.Class
 > import Control.Concurrent(forkIO)
 > import Data.Monoid
+> import Control.Arrow((***),(&&&),(|||))
 >
 > -- from the contravariant package 
 > import Data.Functor.Contravariant
@@ -185,48 +174,42 @@
 
 
 
------- CPP MACROS ------
 
-These macros are only provided by cabal unfortunately.... makes it difficult to
-work with GHCi:
+TODO
+-----
 
-#if !MIN_VERSION_base(4,3,0)
-> void :: (Monad m)=> m a -> m ()
-> void = (>> return ())
-#endif
+0.4
+    - allow destructuring using UndecidableInstances (see mockup) on spawn, allowing for new, awesome synchronization semantics!
+    - make that also work with Behaviors of arbitrary input types using new GHC generics!
 
-------------------------
 
-TODO
------
- 0.3.0:
-    - define natural transformation combinators (in IO unfortunately) a.la.
-      'categories' for Mailbox. So
-        - :: Mailbox (a,b) -> (Mailbox a, Mailbox b)  -- divide?
-        - :: Mailbox a -> Mailbox b -> Mailbox (Either a b) -- add?
-        - etc...
-      put these in a separate sub-module, optionally import, mention how an
-      extension to actor model or something
-    - allow supplying the first input message for an actor during spawn. This is
-      awkward otherwise. Include in same sub-module as above?
-    - performance testing:
+Later:
+    - performance tuning / benchmarking:
+        + look at interface file: ghc -ddump-hi Control/Concurrent/Actors.hs -O -c
+        + remove current PRAGMA
+        - close browser and everything, do a fake quick benchmark to get clock info
+        - be more controlled about the source lists (do once before defaultMain), use 'evaluate'
+        - run with +RTS -s and make sure everything is 0
+        - see if case-based nil is better
+        - get accurate baseline comparison between actors and set
+        - use INLINABLE
+        - test again with SPECIALIZE instead
+        - try adding INLINE to all with higher-order args (or higher-order newtype wrappers)
+           and make sure our LHS looks good for inlining
+        - specialize `Action i (Behavior i)` or allow lots of unfolding... ? Optimize those loops, somehow. Rewrite rules?
         - take a look at threadscope for random tree test
-        - get complete code coverage into simple test module
+        - look at "let floating" and INLINEABLE to get functions with "fully-applied (syntactically) LHS"
+        - compare with previous version (cp to /tmp to use previous version)
+    - get complete code coverage into simple test module
     - interesting solution to exit detection: 
         http://en.wikipedia.org/wiki/Huang%27s_algorithm
-    - better method for waiting for threads to complete. should probably use
-       actor message passing
-    - look into whether we should use Text lib instead of strings?
-      OverloadedStrings?
-        -import Data.String, make polymorphic over IsString
-        -test if this lets us use it in importing module w/ OverloadedStrings
-        extension
-    - structured declarative and unit tests
-    - some sort of exception handling technique via Actors
-        (look at enumerator package)
-    - strict send' function
-
-Later:
+    - dynamically-bounded chans, based on number of writers to control
+      producer/consumer issues? Possibly add more goodies to chan-split
+          see: http://hackage.haskell.org/package/stm-chans
+    - look at what Functor/Contravariant for read/write ends, and corresponding
+      natural transformations those allow suggest about limits of Actor model
+      and investigate inverse of Actors (Reducers?)
+    - create an experimental Collectors sub-module
     - investigate ways of positively influencing thread scheduling based on
        actor work agenda?
     - export some more useful Actors and global thingies
@@ -236,7 +219,13 @@
         - an actor that sends a random stream?
         - a pre-declared Mailbox for IO?
 
- Eventualy:
+ Eventually:
+    - some sort of exception handling technique (using actors?)
+    - abilty to launch an actor that automatically "replicates" if its chan needs more
+       consumers. This should probably be restricted to an `Action i ()` that we
+       repeat.
+    - can we automatically throttle producers on an Actor system level,
+      optimizing message flow with some algorithm?
     - provide an "adapter" for amazon SQS, allowing truly distributed message
       passing
     - investigate erlang-style selective receive (using Alternative?)
@@ -256,32 +245,79 @@
         (maybe letting us use useful enumerators)
      ...also now pipes, conduits, etc. etc.
 
+     - study ambient/join/fusion calculi for clues as to where it's really at
 
+
 CHAN TYPES
 ==========
 
+By defining our Mailbox as the bare "send" operation we get a very convenient
+way of defining contravariant instance, without all the overhead we had before,
+while ALSO now supporting some great natural transformations on Mailboxes &
+Messages.
+
+We use this newtype to get 'Contravariant' for free, possibly revealing other
+insights:
+
+> type Sender a = Op (IO ()) a
+>
+> mailbox :: (a -> IO ()) -> Mailbox a
+> mailbox = Mailbox . Op
+>
+> runMailbox :: Mailbox a -> a -> IO ()
+> runMailbox = getOp . sender
+>
+> mkMailbox :: InChan a -> Mailbox a
+> mkMailbox = mailbox . writeChan
+>
+> mkMessages :: OutChan a -> Messages a
+> mkMessages = Messages . readChan
+>
 > -- | One can 'send' a messages to a @Mailbox@ where it will be processed
 > -- according to an actor\'s defined 'Behavior'
-> newtype Mailbox a = Mailbox { inChan :: InChan a }
+> newtype Mailbox a = Mailbox { sender :: Sender a }
 >       deriving (Contravariant)
->
 
 We don't need to expose this thanks to the miracle of MonadFix and recursive do,
 but this can be generated via the NewSplitChan class below if the user imports
 the library:
 
-> newtype Messages a = Messages { outChan :: OutChan a }
+> newtype Messages a = Messages { readMsg :: IO a }
 >       deriving (Functor) 
 >
 > -- Not sure how to derive this or if possible:
 > instance SplitChan Mailbox Messages where
->     readChan = readChan . outChan
->     writeChan = writeChan . inChan
->     writeList2Chan = writeList2Chan . inChan
+>     readChan = readMsg
+>     writeChan = runMailbox
 >
 > instance NewSplitChan Mailbox Messages where
->     newSplitChan = fmap (\(i,o)-> (Mailbox i, Messages o)) newSplitChan
+>     newSplitChan = (mkMailbox *** mkMessages) `fmap` newSplitChan
+
+
+For Mailboxes we can define all transformations associated with Cartesian and 
+CoCartesian (from 'categories') but where the category is Dual (->), i.e. the
+order of the transformation is flipped.
+
+I don't know if/how these precisely fit into an existing class, but for now here
+are a handful of useful combinators:
+
+> coproductMb :: Mailbox a -> Mailbox b -> Mailbox (Either a b) 
+> coproductMb m1 m2 = mailbox $ either (writeChan m1) (writeChan m2)
 >
+> zipMb :: Mailbox a -> Mailbox b -> Mailbox (a,b) 
+> zipMb m1 m2 = mailbox $ \(a,b) -> writeChan m1 a >> writeChan m2 b
+>
+> -- | > productMb = contramap Left &&& contramap Right
+> productMb :: Mailbox (Either a b) -> (Mailbox a, Mailbox b)
+> productMb = contramap Left &&& contramap Right
+>
+> -- | > faninMb f g = contramap (f ||| g)
+> faninMb :: (a -> c) -> (b -> c)-> Mailbox c -> Mailbox (Either a b) 
+> faninMb f g = contramap (f ||| g)
+>
+> -- | > fanoutMb f g = contramap (f &&& g)
+> fanoutMb :: (a -> b) -> (a -> c) -> Mailbox (b,c) -> Mailbox a
+> fanoutMb f g = contramap (f &&& g)
 
 
 
@@ -353,8 +389,25 @@
 > send :: (MonadIO m, SplitChan c x)=> c a -> a -> m ()
 > send b = liftIO . writeChan b
 
+> -- | A strict 'send':
+> --
+> -- > send' b a = a `seq` send b a
+> send' :: (MonadIO m, SplitChan c x)=> c a -> a -> m ()
+> send' b a = a `seq` send b a
 
+> infixr 1 <->
+>
+> -- | Like 'send' but supports chaining sends by returning the Mailbox.
+> -- Convenient for initializing an Actor with its first input after spawning,
+> -- e.g.
+> --
+> -- >     do mb <- 0 <-> spawn foo
+> (<->) :: (MonadIO m, SplitChan c x)=> a -> m (c a) -> m (c a)
+> a <-> mmb = mmb >>= \mb-> send mb a >> return mb
 
+
+
+
 FORKING AND RUNNING ACTORS:
 ===========================
 
@@ -389,8 +442,11 @@
 --------------
 
 > -- | Fork an actor performing the specified 'Behavior'. /N.B./ an actor 
-> -- begins execution of its 'headBehavior' only after a mesage has been 
-> -- received. See also 'spawn_'.
+> -- begins execution of its 'headBehavior' only after a message has been 
+> -- received; for sending an initial message to an actor right after 'spawn'ing
+> -- it, ('<|>') can be convenient.
+> --
+> -- See also 'spawn_'.
 > spawn :: (MonadIO m)=> Behavior i -> m (Mailbox i)
 > spawn b = do
 >     (m,s) <- liftIO newSplitChan
diff --git a/Control/Concurrent/Actors/Behavior.lhs b/Control/Concurrent/Actors/Behavior.lhs
--- a/Control/Concurrent/Actors/Behavior.lhs
+++ b/Control/Concurrent/Actors/Behavior.lhs
@@ -1,9 +1,6 @@
-> {-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}
-> -- Since we don't get a MonadFix instance for MaybeT from transformers:
-> {-# OPTIONS_GHC -fno-warn-orphans #-}
+> {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 > module Control.Concurrent.Actors.Behavior
 >     where
-> 
 
 Our main data types for actors and behaviors are defined in this private module.
 We may expose this if it is useful to people:
@@ -29,6 +26,9 @@
 A Behavior wraps an Action i a, into a list-like sequence of actions to perform
 over inputs:
 
+> -- | An actor is created by 'Control.Concurrent.Actors.spawn'ing a @Behavior@. Behaviors consist of a
+> -- composed 'Action' that is executed when a message is 'Control.Concurrent.Actors.received' and
+> -- returns the @Behavior@ for processing the next input.
 > newtype Behavior i = Receive { headAction :: Action i (Behavior i) }
 > 
 > instance Contravariant Behavior where
@@ -39,7 +39,7 @@
 This is essentially a marriage of the Monoid [] instance with Action's
 Alternative instance, and I am mostly convinced it is right and has utility:
 
-> -- | @b1 `mplus` b2@ has the 'headAction' of @b2@ begin where the 'yield'
+> -- | @b1 `mplus` b2@ has the 'headAction' of @b2@ begin where the 'Control.Concurrent.Actors.yield'
 > -- occured in @b1@, i.e. @b2@\'s first input will be the final input handed to
 > -- @b1@.
 > instance Monoid (Behavior i) where
@@ -54,24 +54,26 @@
 will be useful:
 
 
+> -- | In the Actor Model, at each step an actor...
+> -- 
+> --     - processes a single 'Control.Concurrent.Actors.received' message
+> --     
+> --     - may 'Control.Concurrent.Actors.spawn' new actors
+> --     
+> --     - may 'Control.Concurrent.Actors.send' messages to other actors
+> --     
+> --     - 'return's the 'Behavior' for processing the /next/ message
+> -- 
+> -- These actions take place within the @Action i@ monad, where @i@ is the type
+> -- of the input message the actor receives.
+> --
+> -- /N.B.:/ the MonadIO instance here is an abstraction leak. An example of a
+> -- good use of 'liftIO' might be to give an @Action@ access to a source of
+> -- randomness.
 > newtype Action i a = Action { readerT :: ReaderT i (MaybeT IO) a }
 >         deriving (Monad, MonadIO, MonadPlus, MonadReader i,
 >                   Functor, Applicative, Alternative, MonadFix)
 > 
-
-
------- CPP MACROS ------
-
-This should end up in the next version of 'transformers':
-   http://www.haskell.org/pipermail/libraries/2011-April/016201.html
-
-#if !MIN_VERSION_transformers(0,3,0)
-> instance (MonadFix m) => MonadFix (MaybeT m) where
->    mfix f = MaybeT $ mfix (runMaybeT . f . unJust)
->      where unJust = maybe (error "mfix MaybeT: Nothing") id
-#endif
-
-------------------------
 
 
 Some helpers for wrapping / unwrapping:
diff --git a/simple-actors.cabal b/simple-actors.cabal
--- a/simple-actors.cabal
+++ b/simple-actors.cabal
@@ -7,7 +7,7 @@
 -- The package version. See the Haskell package versioning policy
 -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
 -- standards guiding when and how versions should be incremented.
-Version:             0.2.1
+Version:             0.3.0
 
 -- A short (one-line) description of the package.
 Synopsis:            A library for more structured concurrent programming, based
@@ -21,10 +21,17 @@
                      single input value, perform some 'Action's, and return the
                      Behavior to process the next input message it receives.
                      .
-                     /CHANGES/ 0.2.0 - 0.2.1:
+                     /CHANGES/ 0.2.1 - 0.3:
                      .
-                     - constrain version of chan-split
+                     - added (@\<-\>@) convenience operator, and strict @send'@
+                     .
+                     - add composition\/transformation functions for Mailboxes
+                     .
+                     - drop support for older base and transformers, no more CPP
+                     .
+                     - depend on chan-split 0.4
 
+
 -- The license under which the package is released.
 License:             BSD3
 
@@ -64,10 +71,10 @@
   Exposed-modules:     Control.Concurrent.Actors
   
   -- Packages needed in order to build this package.
-  Build-depends:       base >= 4 && < 5    
-                     , chan-split <= 0.3.0
+  Build-depends:       base >= 4.3 && < 5    
+                     , chan-split >= 0.4.0
                      , mtl >= 2
-                     , transformers
+                     , transformers >= 0.3
                      , contravariant
                     
   
