diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013-2014 Jan Bracker, Lennart Spitzner.
+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.
+  * The names of this library's contributors may not 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/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/example/Example.hs b/example/Example.hs
new file mode 100644
--- /dev/null
+++ b/example/Example.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Main where
+
+
+
+import Control.Monad.MultiState
+
+import Control.Applicative ( (<$>), (<*>) )
+
+import Control.Monad.Trans ( lift )
+
+{-
+Small example showing
+  1) a MultiState containing a Char and a [Char],
+  2) the polymorphic mGet,
+  3) how to initially put values into the MultiState using withMultiState,
+  4) the type inference at work - note that we omitted all type signatures.
+-}
+
+--examplePrint :: MultiStateT (Cons [Char] (Cons Char Null)) IO ()
+-- or more general:
+--examplePrint :: ( MonadMultiState [Char] m
+--                , MonadMultiState Char m
+--                , m~MultiStateT x IO)
+--             => m ()
+examplePrint = do
+  c  <- mGet
+  cs <- mGet
+  lift $ putStrLn (c:cs)
+
+exampleAction = do
+  examplePrint
+  mSet 'J'
+  examplePrint
+
+main = evalMultiStateT
+     $ withMultiState 'H'
+     $ withMultiState "ello, World!"
+     $ exampleAction
+
+-- output of main:
+--  "Hello, World!
+--   Jello, World!
+--  "
+
+--whatIsNotPossible :: MultiStateT (Cons [Char] Null) IO ()
+--whatIsNotPossible = mGet >>= (lift . print) -- type ambiguous
+
+-- another thing that is not directly possible is the restriction to
+-- specific values, i.e. a function
+--  restrict :: MultiStateT xvalues m a -> MultiStateT yvalues m a
+-- where yvalues is a "superset" of xvalues.
+
+--TODO: example with mGetRaw and withMultiStates
diff --git a/multistate.cabal b/multistate.cabal
new file mode 100644
--- /dev/null
+++ b/multistate.cabal
@@ -0,0 +1,97 @@
+Name:          multistate
+Version:       0.1.1
+Cabal-Version: >= 1.8
+Build-Type:    Simple
+license:       BSD3
+license-file:  LICENSE
+Copyright:     Jan Bracker, Lennart Spitzner
+Maintainer:    Lennart Spitzner <lsp@informatik.uni-kiel.de>
+Author:        Jan Bracker, Lennart Spitzner
+Homepage:      https://github.com/lspitzner/multistate
+Bug-reports:   https://github.com/lspitzner/multistate/issues
+Stability:     Experimental
+category:      Control
+tested-with:   GHC == 7.8.2
+
+Synopsis: like mtl's ReaderT/StateT, but more than one contained value/type.
+Description:
+  When using multiple ReaderT's or StateT's in the same monad stack, it becomes
+  necessary to lift the operations in order to affect a specific transformer.
+  Using heterogenous lists (type level functions), a GADT and a corresponding
+  type class, this package provides transformers that remove that necessity:
+  MultiReaderT/MultiStateT can contain a heterogenous list of values.
+  The type inferred for the getter/setter determines which value is
+  read/written.
+  See the Example application for some very basic usage.
+  This package currently lacks a complete set of "lifting instances", i.e.
+  instance definitions for classes such as mtl's MonadReader "over" the newly
+  introduced monad transformers. These "lifting instances" would be necessary
+  to achieve full compatability with existing transformers. Ping me if you
+  find anything specific missing.
+
+source-repository head
+  type: git
+  location: git@github.com:lspitzner/multistate.git
+
+flag build-test
+  description: Build the MultiState-test test program
+  default: False
+
+flag build-example
+  description: Build the MultiState-example example program
+  default: False  
+
+library {
+  exposed-modules:
+    Control.Monad.MultiState
+    Control.Monad.MultiReader
+  other-modules:
+    Data.HList.HList
+  build-depends:
+    base >=4 && <6,
+    mtl >=2 && <3,
+    tfp >=0.8,
+    transformers == 0.3.*
+  extensions:
+    GADTs
+    TypeFamilies
+    MultiParamTypeClasses
+    FunctionalDependencies
+    FlexibleInstances
+    OverlappingInstances
+    UndecidableInstances
+  ghc-options: -Wall
+  hs-source-dirs: src
+}
+
+executable multistate-test {
+  if flag(build-test) {
+    buildable: True
+    build-depends:
+      multistate,
+      base >= 4 && < 6,
+      transformers == 0.3.*,
+      tfp >=0.8
+  } else {
+    buildable: False
+  }
+  ghc-options: -Wall
+  main-is: Test.hs
+  hs-source-dirs: test
+}
+
+executable multistate-example {
+  if flag(build-example) {
+    buildable: True
+    build-depends:
+      multistate,
+      base >= 4 && < 6,
+      transformers == 0.3.*,
+      tfp >=0.8,
+      mtl >=2 && <3
+  } else {
+    buildable: False
+  }
+  main-is: Example.hs
+  hs-source-dirs: example
+}
diff --git a/src/Control/Monad/MultiReader.hs b/src/Control/Monad/MultiReader.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/MultiReader.hs
@@ -0,0 +1,172 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverlappingInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+module Control.Monad.MultiReader
+  ( MultiReaderT(..)
+  , MultiReaderTNull
+  , MultiReader
+  , MonadMultiReader(..)
+  , mAskRaw
+  , withMultiReader
+  , withMultiReaders
+  , evalMultiReaderT
+  , evalMultiReaderTWithInitial
+  , mapMultiReaderT
+  , Cons -- re-export that stuff to allow writing type signatures.
+  , Null
+) where
+
+
+
+import Data.HList.HList
+
+import Control.Monad.State.Strict ( StateT(..)
+                                  , MonadState(..)
+                                  , evalStateT
+                                  , mapStateT )
+import Control.Monad.Trans.Class  ( MonadTrans
+                                  , lift )
+import Control.Monad.Writer.Class ( MonadWriter
+                                  , listen
+                                  , tell
+                                  , writer
+                                  , pass )
+
+import Types.Data.List            ( Cons
+                                  , Null
+                                  , Append )
+import Data.Functor.Identity      ( Identity )
+
+import Control.Applicative        ( Applicative(..) )
+import Control.Monad              ( liftM
+                                  , ap )
+
+
+
+newtype MultiReaderT x m a = MultiReaderT {
+  runMultiReaderTRaw :: StateT (HList x) m a
+}
+
+type MultiReaderTNull = MultiReaderT Null
+
+type MultiReader x a = MultiReaderT x Identity a
+
+class ContainsType a c where
+  setHListElem :: a -> HList c -> HList c
+  getHListElem :: HList c -> a
+
+class (Monad m) => MonadMultiReader a m where
+  mAsk :: m a
+
+{-
+it might make seem straightforward to define the following class that
+corresponds to other transformer classes. But while we can define the the
+class and its instances, there is a problem we try to use it, assuming that we
+do not want to annotate the full type signature of the config:
+  the type of the config can not be inferred properly. we would need a feature
+  like "infer, as return type for this function, the only type for
+  which there exists a valid chain of instance definitions that is needed to
+  by this function".
+  In other words, it is impossible to use the mAskRaw function without
+  binding a concrete type for c, because otherwise the inference runs into
+  some overlapping instances.
+For this reason, I removed this type class and created a non-class function
+mAskRaw, for which the type inference works because it involves no
+type classes.
+  lennart spitzner
+-}
+
+--class (Monad m) => MonadMultiReaderRaw c m where
+--  mAskRaw :: m (HList c)
+
+--instance (MonadTrans t, Monad (t m), MonadMultiReaderRaw c m)
+--      => MonadMultiReaderRaw c (t m) where
+--  mAskRaw = lift $ mAskRaw
+
+--instance (Monad m) => MonadMultiReaderRaw a (MultiReaderT a m) where
+--  mAskRaw = MultiReaderT $ get
+
+instance ContainsType a (Cons a xs) where
+  setHListElem a (TCons _ xs) = TCons a xs
+  getHListElem (TCons x _) = x
+
+instance (ContainsType a xs) => ContainsType a (Cons x xs) where
+  setHListElem a (TCons x xs) = TCons x $ setHListElem a xs
+  getHListElem (TCons _ xs) = getHListElem xs
+
+instance (Functor f) => Functor (MultiReaderT x f) where
+  fmap f = MultiReaderT . fmap f . runMultiReaderTRaw
+
+instance (Applicative m, Monad m) => Applicative (MultiReaderT x m) where
+  pure = MultiReaderT . pure
+  (<*>) = ap
+
+instance Monad m => Monad (MultiReaderT x m) where
+  return = MultiReaderT . return
+  k >>= f = MultiReaderT $ runMultiReaderTRaw k >>= (runMultiReaderTRaw.f)
+
+instance MonadTrans (MultiReaderT x) where
+  lift = MultiReaderT . lift
+
+withMultiReader :: Monad m
+                => x
+                -> MultiReaderT (Cons x xs) m a
+                -> MultiReaderT xs m a
+withMultiReader x k = MultiReaderT $ do
+  s <- get
+  (a, TCons _ s') <- lift $ runStateT (runMultiReaderTRaw k) (TCons x s)
+  put s'
+  return a
+
+withMultiReaders :: Monad m
+                 => HList xs
+                 -> MultiReaderT (Append xs ys) m a
+                 -> MultiReaderT ys m a
+withMultiReaders TNull = id
+withMultiReaders (TCons x xs) = withMultiReaders xs . withMultiReader x
+
+instance (Monad m, ContainsType a c)
+      => MonadMultiReader a (MultiReaderT c m) where
+  mAsk = MultiReaderT $ liftM getHListElem get
+
+instance (MonadTrans t, Monad (t m), MonadMultiReader a m)
+      => MonadMultiReader a (t m) where
+  mAsk = lift $ mAsk
+
+mAskRaw :: Monad m => MultiReaderT a m (HList a)
+mAskRaw = MultiReaderT get
+
+evalMultiReaderT :: Monad m => MultiReaderT Null m a -> m a
+evalMultiReaderT k = evalStateT (runMultiReaderTRaw k) TNull
+
+evalMultiReaderTWithInitial :: Monad m
+                            => HList a
+                            -> MultiReaderT a m b
+                            -> m b
+evalMultiReaderTWithInitial c k = evalStateT (runMultiReaderTRaw k) c
+
+mapMultiReaderT :: (m (a, HList w)
+                -> m' (a', HList w))
+                -> MultiReaderT w m a
+                -> MultiReaderT w m' a'
+mapMultiReaderT f = MultiReaderT . mapStateT f . runMultiReaderTRaw
+
+-- foreign lifting instances
+
+instance (MonadState s m) => MonadState s (MultiReaderT c m) where
+  put   = lift . put
+  get   = lift $ get
+  state = lift . state
+
+instance (MonadWriter w m) => MonadWriter w (MultiReaderT c m) where
+  writer = lift . writer
+  tell   = lift . tell
+  listen = MultiReaderT .
+    mapStateT (liftM (\((a,w), w') -> ((a, w'), w)) . listen) .
+    runMultiReaderTRaw
+  pass = MultiReaderT .
+    mapStateT (pass . liftM (\((a, f), w) -> ((a, w), f))) .
+    runMultiReaderTRaw  
diff --git a/src/Control/Monad/MultiState.hs b/src/Control/Monad/MultiState.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/MultiState.hs
@@ -0,0 +1,146 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverlappingInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+module Control.Monad.MultiState
+  ( MultiStateT(..)
+  , MultiStateTNull
+  , MultiState
+  , MonadMultiState(..)
+  , mGetRaw
+  , withMultiState
+  , withMultiStates
+  , evalMultiStateT
+  , evalMultiStateTWithInitial
+  , mapMultiStateT
+  , Cons -- re-export that stuff to allow writing type signatures.
+  , Null
+) where
+
+
+
+import Data.HList.HList
+
+import Control.Monad.State.Strict ( StateT(..)
+                                  , MonadState(..)
+                                  , evalStateT
+                                  , mapStateT )
+import Control.Monad.Trans.Class  ( MonadTrans
+                                  , lift )
+import Control.Monad.Writer.Class ( MonadWriter
+                                  , listen
+                                  , tell
+                                  , writer
+                                  , pass )
+
+import Types.Data.List            ( Cons
+                                  , Null
+                                  , Append )
+import Data.Functor.Identity      ( Identity )
+
+import Control.Applicative        ( Applicative(..) )
+import Control.Monad              ( liftM
+                                  , ap )
+
+
+
+newtype MultiStateT x m a = MultiStateT {
+  runMultiStateTRaw :: StateT (HList x) m a
+}
+
+type MultiStateTNull = MultiStateT Null
+
+type MultiState x a = MultiStateT x Identity a
+
+class ContainsType a c where
+  setHListElem :: a -> HList c -> HList c
+  getHListElem :: HList c -> a
+
+class (Monad m) => MonadMultiState a m where
+  mSet :: a -> m ()
+  mGet :: m a
+
+instance ContainsType a (Cons a xs) where
+  setHListElem a (TCons _ xs) = TCons a xs
+  getHListElem (TCons x _) = x
+
+instance (ContainsType a xs) => ContainsType a (Cons x xs) where
+  setHListElem a (TCons x xs) = TCons x $ setHListElem a xs
+  getHListElem (TCons _ xs) = getHListElem xs
+
+instance (Functor f) => Functor (MultiStateT x f) where
+  fmap f = MultiStateT . fmap f . runMultiStateTRaw
+
+instance (Applicative m, Monad m) => Applicative (MultiStateT x m) where
+  pure = MultiStateT . pure
+  (<*>) = ap
+
+instance Monad m => Monad (MultiStateT x m) where
+  return = MultiStateT . return
+  k >>= f = MultiStateT $ runMultiStateTRaw k >>= (runMultiStateTRaw.f)
+
+instance MonadTrans (MultiStateT x) where
+  lift = MultiStateT . lift
+
+withMultiState :: Monad m
+               => x
+               -> MultiStateT (Cons x xs) m a
+               -> MultiStateT xs m a
+withMultiState x k = MultiStateT $ do
+  s <- get
+  (a, TCons _ s') <- lift $ runStateT (runMultiStateTRaw k) (TCons x s)
+  put s'
+  return a
+
+withMultiStates :: Monad m
+                => HList xs
+                -> MultiStateT (Append xs ys) m a
+                -> MultiStateT ys m a
+withMultiStates TNull = id
+withMultiStates (TCons x xs) = withMultiStates xs . withMultiState x
+
+instance (Monad m, ContainsType a c)
+      => MonadMultiState a (MultiStateT c m) where
+  mSet v = MultiStateT $ get >>= (put . setHListElem v)
+  mGet = MultiStateT $ liftM getHListElem get
+
+instance (MonadTrans t, Monad (t m), MonadMultiState a m)
+      => MonadMultiState a (t m) where
+  mSet = lift . mSet
+  mGet = lift $ mGet
+
+evalMultiStateT :: Monad m => MultiStateT Null m a -> m a
+evalMultiStateT k = evalStateT (runMultiStateTRaw k) TNull
+
+evalMultiStateTWithInitial :: Monad m
+                           => HList a
+                           -> MultiStateT a m b
+                           -> m b
+evalMultiStateTWithInitial c k = evalStateT (runMultiStateTRaw k) c
+
+mGetRaw :: Monad m => MultiStateT a m (HList a)
+mGetRaw = MultiStateT get
+
+mapMultiStateT :: (m (a, HList w) -> m' (a', HList w))
+               -> MultiStateT w m  a
+               -> MultiStateT w m' a'
+mapMultiStateT f = MultiStateT . mapStateT f . runMultiStateTRaw
+
+-- foreign lifting instances
+
+instance (MonadState s m) => MonadState s (MultiStateT c m) where
+  put   = lift . put
+  get   = lift $ get
+  state = lift . state
+
+instance (MonadWriter w m) => MonadWriter w (MultiStateT c m) where
+  writer = lift . writer
+  tell   = lift . tell
+  listen = MultiStateT .
+    mapStateT (liftM (\((a,w), w') -> ((a, w'), w)) . listen) .
+    runMultiStateTRaw
+  pass = MultiStateT .
+    mapStateT (pass . liftM (\((a, f), w) -> ((a, w), f))) .
+    runMultiStateTRaw  
diff --git a/src/Data/HList/HList.hs b/src/Data/HList/HList.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/HList/HList.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Data.HList.HList(
+  HList(..)
+) where
+
+
+
+import Prelude hiding (reverse)
+
+import Types.Data.List ( Cons, Null )
+
+
+
+data HList a where
+  TCons :: x -> HList xs -> HList (Cons x xs)
+  TNull :: HList Null
+
+instance Show (HList Null) where
+  show _ = "()"
+
+instance (Show a, Show (HList b)) => Show (HList (Cons a b)) where
+  show (TCons x y) = "(" ++ show x ++ "," ++ show y ++ ")"
diff --git a/test/Test.hs b/test/Test.hs
new file mode 100644
--- /dev/null
+++ b/test/Test.hs
@@ -0,0 +1,207 @@
+module Main where
+
+
+
+import Data.Functor.Identity
+import qualified Control.Monad.MultiState as MS
+import qualified Control.Monad.MultiReader as MR
+import Types.Data.List ( Cons, Null )
+
+import Control.Applicative ( Applicative, (<$>), (<*>) )
+
+
+
+type Tests = [(Bool, String)]
+
+runEvalMS :: MS.MultiStateT Null Identity a -> a
+runEvalMS = runIdentity . MS.evalMultiStateT
+runEvalMR :: MR.MultiReaderT Null Identity a -> a
+runEvalMR = runIdentity . MR.evalMultiReaderT
+
+runnerMS :: a -> MS.MultiStateT (Cons a Null) Identity a -> a
+runnerMS x m = runIdentity $ MS.evalMultiStateT $ MS.withMultiState x m
+runnerMR :: a -> MR.MultiReaderT (Cons a Null) Identity a -> a
+runnerMR x m = runIdentity $ MR.evalMultiReaderT $ MR.withMultiReader x m
+
+runnerMS_ :: a -> MS.MultiStateT (Cons a Null) Identity b -> a
+runnerMS_ x m = runIdentity
+              $ MS.evalMultiStateT
+              $ MS.withMultiState x (m >> MS.mGet)
+runnerMR_ :: a -> MR.MultiReaderT (Cons a Null) Identity b -> a
+runnerMR_ x m = runIdentity
+              $ MR.evalMultiReaderT
+              $ MR.withMultiReader x (m >> MR.mAsk)
+
+intRunnerMS :: Int -> MS.MultiStateT (Cons Int Null) Identity Int -> Int
+intRunnerMS = runnerMS
+intRunnerMS_ :: Int -> MS.MultiStateT (Cons Int Null) Identity b -> Int
+intRunnerMS_ = runnerMS_
+intRunnerMR :: Int -> MR.MultiReaderT (Cons Int Null) Identity Int -> Int
+intRunnerMR = runnerMR
+intRunnerMR_ :: Int -> MR.MultiReaderT (Cons Int Null) Identity b -> Int
+intRunnerMR_ = runnerMR_
+
+mrAskTuple :: ( Applicative m
+              , MR.MonadMultiReader a m
+              , MR.MonadMultiReader b m)
+           => m (a,b)
+mrAskTuple = (,) <$> MR.mAsk <*> MR.mAsk
+msGetTuple :: ( Applicative m
+              , MS.MonadMultiState a m
+              , MS.MonadMultiState b m)
+           => m (a,b)
+msGetTuple = (,) <$> MS.mGet <*> MS.mGet
+
+testsMultiState :: Tests
+testsMultiState =
+  [
+    (1 == runIdentity (Identity (1::Int))
+    , "identity"),
+    (2 == intRunnerMS_ 2 (return ())
+    , "multistate getConfig"),
+    (3 == intRunnerMS_ 100 (MS.mSet (3::Int))
+    , "multistate setConfig"),
+    (4 == intRunnerMS_ 4 (MS.mGet >>= \x -> MS.mSet (x::Int))
+    , "multistate setConfig"),
+    (5 == intRunnerMS (4::Int) (MS.withMultiState (5::Int) MS.mGet)
+    , "multistate nesting"),
+    (6 == intRunnerMS (4::Int) (   MS.mSet (100::Int)
+                                >> MS.withMultiState (6::Int) MS.mGet)
+    , "multistate nesting"),
+    (7 == intRunnerMS (4::Int) (   MS.withMultiState (100::Int)
+                                     $ MS.mSet (7::Int)
+                                >> MS.mGet)
+    , "multistate nesting"),
+    ((True, 'a') == ( runEvalMS
+                    $ MS.withMultiState True
+                    $ MS.withMultiState 'a'
+                    $ msGetTuple )
+    , "multistate multiple types"),
+    ((True, 'b') == ( runEvalMS
+                    $ MS.withMultiState True
+                    $ MS.withMultiState 'a'
+                    $ MS.withMultiState 'b'
+                    $ msGetTuple )
+    , "multistate multiple types"),
+    ((False, 'a') == ( runEvalMS
+                     $ MS.withMultiState True
+                     $ MS.withMultiState 'a'
+                     $ MS.withMultiState False
+                     $ msGetTuple )
+    , "multistate multiple types"),
+    (test13MS
+    , "askRaw")
+  ]
+
+testsMultiReader :: Tests
+testsMultiReader =
+  [
+    (1 == runIdentity (Identity (1::Int))
+    , "identity"),
+    (2 == intRunnerMR_ 2 (return ())
+    , "multistate getConfig"),
+    (5 == intRunnerMR (4::Int) (MR.withMultiReader (5::Int) MR.mAsk)
+    , "multistate nesting"),
+    ((True, 'a') == ( runEvalMR
+                    $ MR.withMultiReader True
+                    $ MR.withMultiReader 'a'
+                    $ mrAskTuple )
+    , "multistate multiple types"),
+    ((True, 'b') == ( runEvalMR
+                    $ MR.withMultiReader True
+                    $ MR.withMultiReader 'a'
+                    $ MR.withMultiReader 'b'
+                    $ mrAskTuple )
+    , "multistate multiple types"),
+    ((False, 'a') == ( runEvalMR
+                     $ MR.withMultiReader True
+                     $ MR.withMultiReader 'a'
+                     $ MR.withMultiReader False
+                     $ mrAskTuple )
+    , "multistate multiple types"),
+    (test13MR
+    , "getRaw")
+  ]
+
+tests :: Tests
+tests = testsMultiState ++ testsMultiReader
+
+test13MR :: Bool
+test13MR = runIdentity
+         $ MR.evalMultiReaderT
+         $ MR.withMultiReader True
+         $ MR.withMultiReader 'a'
+         $ do
+  c <- MR.mAskRaw
+  return $ runIdentity
+         $ MR.evalMultiReaderT
+         $ MR.withMultiReaders c
+         $ do
+    b <- MR.mAsk
+    return (b::Bool)
+
+test13MS :: Bool
+test13MS = runIdentity
+         $ MS.evalMultiStateT
+         $ MS.withMultiState True
+         $ MS.withMultiState 'a'
+         $ do
+  c <- MS.mGetRaw
+  return $ runIdentity
+         $ MS.evalMultiStateT
+         $ MS.withMultiStates c
+         $ do
+    b <- MS.mGet
+    return (b::Bool)
+
+main :: IO ()
+main = do
+  mapM_ (putStrLn . ("error: "++) . snd) $ filter (\(b, _) -> not b) tests
+  putStrLn $    "ran "
+             ++ show (length tests)
+             ++ " tests (no further output = good)"
+  return ()
+
+{-
+
+main = do
+  evalStateT
+    (evalMultiReaderT $ withConfig 'a' $ do
+        x <- withConfig 'b' getConfig
+        lift $ lift $ print (x::Char)
+        y <- get
+        lift $ lift $ print (y::Int)
+        return ()
+    )
+    (1::Int)
+  evalMultiReaderT $ withConfig 'a' $ evalStateT
+    ( do
+        x <- getConfig
+        lift $ lift $ print (x::Char)
+        y <- get
+        lift $ lift $ print (y::Int)
+        return ()
+    )
+    (1::Int)
+
+main = do
+  evalStateT
+    (evalMultiStateT $ withConfig 'a' $ do
+        x <- withConfig 'b' getConfig
+        lift $ lift $ print (x::Char)
+        y <- get
+        lift $ lift $ print (y::Int)
+        return ()
+    )
+    (1::Int)
+  evalMultiStateT $ withConfig 'a' $ evalStateT
+    ( do
+        x <- getConfig
+        lift $ lift $ print (x::Char)
+        y <- get
+        lift $ lift $ print (y::Int)
+        return ()
+    )
+    (1::Int)
+
+-}
