diff --git a/Control/Monad/Trans/Either.hs b/Control/Monad/Trans/Either.hs
new file mode 100644
index 0000000..41f58ca
--- /dev/null
+++ b/Control/Monad/Trans/Either.hs
@@ -0,0 +1,106 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Monad.Trans.Either
+-- Copyright   :  (c) Edward A. Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  ross@soi.city.ac.uk
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- This monad transformer adds the ability to fail or throw exceptions
+-- to a monad.
+--
+-- A sequence of actions succeeds, producing a value, only if all the
+-- actions in the sequence are successful.  If one fails with an error,
+-- the rest of the sequence is skipped and the composite action fails
+-- with that error.
+--
+-- If the value of the error is not required, the variant in
+-- "Control.Monad.Trans.Maybe" may be used instead.
+--
+-- Compared to "Control.Monad.Trans.Error", this transformer does not
+-- require the exception type to be an instance of 'Error' and uses the
+-- default implementation of 'fail' (namely, 'error').
+-----------------------------------------------------------------------------
+module Control.Monad.Trans.Either
+  ( EitherT(..)
+  , eitherT
+  , mapEitherT
+  , hoistEither
+  , left
+  , right
+  ) where
+
+import Control.Applicative
+import Data.Foldable
+import Data.Traversable
+import Data.Monoid
+import Control.Monad.Trans.Class
+import Control.Monad.IO.Class
+import Control.Monad.Fix
+import Control.Monad (liftM)
+
+newtype EitherT e m a = EitherT { runEitherT :: m (Either e a) }
+
+eitherT :: Monad m => (a -> m c) -> (b -> m c) -> EitherT a m b -> m c
+eitherT f g (EitherT m) = m >>= \z -> case z of
+  Left a -> f a
+  Right b -> g b
+{-# INLINE eitherT #-}
+
+left :: Monad m => e -> EitherT e m a
+left = EitherT . return . Left
+{-# INLINE left #-}
+
+right :: Monad m => a -> EitherT e m a
+right = return
+{-# INLINE right #-}
+
+
+mapEitherT :: Functor m => (e -> f) -> (a -> b) -> EitherT e m a -> EitherT f m b
+mapEitherT f g (EitherT m) = EitherT (fmap h m) where
+  h (Left e)  = Left (f e)
+  h (Right a) = Right (g a)
+{-# INLINE mapEitherT #-}
+
+hoistEither :: Monad m => Either e a -> EitherT e m a
+hoistEither = EitherT . return
+{-# INLINE hoistEither #-}
+
+instance Functor m => Functor (EitherT e m) where
+  fmap f = EitherT . fmap (fmap f) . runEitherT
+
+instance (Functor m, Monad m) => Applicative (EitherT e m) where
+  pure a  = EitherT $ return (Right a)
+  EitherT f <*> EitherT v = EitherT $ f >>= \mf -> case mf of
+    Left  e -> return (Left e)
+    Right k -> v >>= \mv -> case mv of
+      Left  e -> return (Left e)
+      Right x -> return (Right (k x))
+
+instance Monad m => Monad (EitherT e m) where
+  return a = EitherT $ return (Right a)
+  m >>= k  = EitherT $ do
+    a <- runEitherT m
+    case a of
+      Left  l -> return (Left l)
+      Right r -> runEitherT (k r)
+
+instance MonadFix m => MonadFix (EitherT e m) where
+  mfix f = EitherT $ mfix $ \a -> runEitherT $ f $ case a of
+    Right r -> r
+    _       -> error "empty mfix argument"
+
+instance MonadTrans (EitherT e) where
+  lift = EitherT . liftM Right
+
+instance MonadIO m => MonadIO (EitherT e m) where
+  liftIO = lift . liftIO
+
+instance Foldable m => Foldable (EitherT e m) where
+  foldMap f = foldMap (either mempty f) . runEitherT
+
+instance (Traversable f) => Traversable (EitherT e f) where
+  traverse f (EitherT a) =
+    EitherT <$> traverse (either (pure . Left) (fmap Right . f)) a
diff --git a/transformers.cabal b/transformers.cabal
index 4a83dc6..dec898d 100644
--- a/transformers.cabal
+++ b/transformers.cabal
@@ -48,6 +48,7 @@ library
     Control.Monad.Trans.Class
     Control.Monad.Trans.Cont
     Control.Monad.Trans.Error
+    Control.Monad.Trans.Either
     Control.Monad.Trans.Identity
     Control.Monad.Trans.List
     Control.Monad.Trans.Maybe
