diff --git a/Control/Monad/Distributive.hs b/Control/Monad/Distributive.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Distributive.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
+
+module Control.Monad.Distributive (Distributive(dist)) where
+
+import qualified Control.Monad.State.Strict as Strict
+import Control.Monad.State
+import Control.Monad.Writer
+import Control.Monad.Reader
+import Control.Monad.Identity
+import Data.Functor.Compose
+
+-- | Monads that distribute over one another.
+class (Monad m, Monad n) => Distributive m n where
+	dist :: m (n t) -> n (m t)
+
+instance (Monad n) => Distributive Maybe n where
+	dist (Just m) = liftM Just m
+	dist Nothing = return Nothing
+
+instance (Monad n) => Distributive (Either t) n where
+	dist (Left x) = return (Left x)
+	dist (Right m) = liftM Right m
+
+instance (Monad n, Monoid x) => Distributive (WriterT x Identity) n where
+	dist wr = let (m, w) = runWriter wr in m >>= \x -> return (tell w >> return x)
+
+instance (Monad n) => Distributive [] n where
+	dist = sequence
+
+instance (Monad m) => Distributive m (Strict.StateT v Identity) where
+	dist m = get >>= \x -> return (m >>= \st -> return $ Strict.evalState st x)
+
+instance (Monad m) => Distributive m (StateT v Identity) where
+	dist m = get >>= \x -> return (m >>= \st -> return $ evalState st x)
+
+instance (Monad m) => Distributive m (ReaderT v Identity) where
+	dist m = ask >>= \x -> return (m >>= \rd -> return $ runReader rd x)
+
+instance (Monad m) => Distributive m Identity where
+	dist m = Identity (m >>= return . runIdentity)
+
+instance (Monad n) => Distributive Identity n where
+	dist (Identity m) = m >>= return . Identity
+
+instance (Distributive n2 n, Distributive m n2, Distributive m n) => Distributive m (Compose n n2) where
+	dist = Compose . liftM dist . dist . liftM getCompose
+
+instance (Distributive m n, Distributive m2 m, Distributive m2 n) => Distributive (Compose m m2) n where
+	dist = liftM Compose . dist . liftM dist . getCompose
+
+join' m = Compose $ join $ liftM (liftM join . dist) m
+
+-- | Monads with a distributive law compose to give another monad.
+instance (Distributive n m) => Monad (Compose m n) where
+	return = Compose . return . return
+	Compose m >>= f = join' (liftM (liftM (getCompose . f)) m)
+
+instance (Monad m) => MonadTrans (Compose m) where
+	lift = Compose . return
+
diff --git a/Control/Monad/IOT.hs b/Control/Monad/IOT.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/IOT.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE MagicHash, UnboxedTuples, Rank2Types #-}
+
+module Control.Monad.IOT (IOT, run) where
+
+import GHC.IO hiding (liftIO)
+import GHC.Prim
+import Control.Monad.Trans (MonadIO(..))
+import Control.Monad.Identity
+import Control.Monad.Morph
+import Control.Monad
+import Control.Applicative
+
+data St = St { unSt :: !(State# RealWorld) }
+
+-- | An IO monad transformer.
+--
+-- I can't run 'IOT'. Instead, I run the monad inside it.
+-- This is done using 'run', and 'hoist' from mmorph.
+--
+-- The combination is only a monad if the parameter monad
+-- isn't nondeterministic. IOT Maybe and IOT State are
+-- monads, but IOT [] and IOT Cont are not.
+--
+-- Should be integrated with STT.
+
+newtype IOT m t = IOT (St -> m (St, t))
+
+instance (Monad m) => Monad (IOT m) where
+	return x = IOT (\s -> return (s, x))
+	IOT f >>= g = IOT (\s -> f s >>= \(s2, x) -> case g x of
+		IOT h -> h s2)
+
+instance (Monad m) => Applicative (IOT m) where
+	pure = return
+	(<*>) = ap
+
+instance (Monad m) => Functor (IOT m) where
+	fmap f m = m >>= return . f
+
+instance (Monad m) => MonadIO (IOT m) where
+	liftIO (IO f) = IOT (\s -> case f (unSt s) of
+		(# s2, x #) -> return (St s2, x))
+
+instance MonadTrans IOT where
+	lift m = IOT (\s -> liftM ((,) s) m)
+
+instance MFunctor IOT where
+	hoist f (IOT g) = IOT (f . g)
+
+-- Flatten two layers into one. mmorph exports 'squash'.
+_squash (IOT f) = IOT (\s -> let IOT g = f s in g s >>= return . snd)
+
+instance MMonad IOT where
+	embed f (IOT g) = _squash $ IOT (f . g)
+
+-- | Run an IOT.
+run :: IOT Identity t -> IO t
+run (IOT f) = IO (\s -> case runIdentity (f (St s)) of
+	(s2, x) -> (# unSt s2, x #))
diff --git a/Control/Monad/Plus.hs b/Control/Monad/Plus.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Plus.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE RankNTypes, TypeOperators #-}
+
+-- | The Plus monad - a free combination of monads. This is very similar to coproducts, but not quite the same.
+--
+--   Coproducts are due to Luth and Ghani, "Composing Monads Using Coproducts," http://www.informatik.uni-bremen.de/~cxl/papers/icfp02.pdf
+module Control.Monad.Plus where
+
+import Control.Monad.Trans
+import Control.Monad.Identity
+import Control.Monad.Product
+import Control.Monad.Morph
+import Control.Applicative
+import Control.Arrow
+
+newtype (m ::+ n) t = Plus { unPlus :: forall x. (MonadPlus x) => (forall u. m u -> x u) -> (forall u. n u -> x u) -> x t }
+
+instance Monad (m ::+ n) where
+	return x = Plus (\_ _ -> return x)
+	Plus f >>= g = Plus (\h i -> f h i >>= \x -> unPlus (g x) h i)
+
+instance Functor (m ::+ n) where
+	fmap f m = m >>= return . f
+
+instance Applicative (m ::+ n) where
+	pure = return
+	(<*>) = ap
+
+instance MonadPlus (m ::+ n) where
+	mzero = Plus (\_ _ -> mzero)
+	mplus (Plus f) (Plus g) = Plus (\h i -> mplus (f h i) (g h i))
+
+inl m = Plus (\h _ -> h m)
+
+inr m = Plus (\_ i -> i m)
+
+instance MonadTrans ((::+) m) where
+	lift = inr
+
+mapPlus :: (forall t. m t -> m1 t) -> (forall t. n t -> n1 t) -> (m ::+ n) t -> (m1 ::+ n1) t
+mapPlus f g (Plus x) = Plus (\h i -> x (h . f) (i . g))
+
+instance MFunctor ((::+) m) where
+	hoist = mapPlus id
+
+comm :: (m ::+ n) t -> (n ::+ m) t
+comm (Plus f) = Plus (flip f)
+
+assoc (Plus f) = Plus (\h i -> f (\m -> unPlus m h (i . inl)) (i . inr))
+
+assoc1 (Plus f) = Plus (\h i -> f (h . inl) (\m -> unPlus m (h . inr) i))
+
+cancelLeft (Plus f) = f (return . runIdentity) id
+
+cancelRight (Plus f) = f id (return . runIdentity)
+
+refl (Plus f) = f id id
+
+instance (MonadPlus m) => MMonad ((::+) m) where
+	embed f = mapPlus refl id . assoc1 . mapPlus id f
+
+-- | Distributivity with monad products.
+distr pls = Product (mapPlus (fst . runProduct) (fst . runProduct) pls, mapPlus (snd . runProduct) (snd . runProduct) pls)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, James Candyu
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of James Candyu nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MonadCompose.cabal b/MonadCompose.cabal
new file mode 100644
--- /dev/null
+++ b/MonadCompose.cabal
@@ -0,0 +1,18 @@
+name:                MonadCompose
+version:             0.1.0.0
+synopsis:            An IO monad transformer
+description:         Methods for composing monads. See also Control.Monad.Trans.Adjoint.
+homepage:            http://alkalisoftware.net
+license:             BSD3
+license-file:        LICENSE
+author:              James Candy
+maintainer:          info@alkalisoftware.net
+-- copyright:           
+category:            Monad
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  exposed-modules:     Control.Monad.IOT, Control.Monad.Distributive, Control.Monad.Plus
+  -- other-modules: 
+  build-depends:       base ==4.6.*, ghc-prim ==0.3.*, mtl ==2.1.*, mmorph ==1.0.*, monad-products, transformers
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
