diff --git a/Control/Monad/StateStack.hs b/Control/Monad/StateStack.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/StateStack.hs
@@ -0,0 +1,210 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving
+           , FlexibleInstances
+           , MultiParamTypeClasses
+  #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Monad.StateStack
+-- Copyright   :  (c) 2011 Brent Yorgey
+-- License     :  BSD-style (see LICENSE)
+-- Maintainer  :  byorgey@cis.upenn.edu
+--
+-- A state monad which allows the state to be saved and restored on a
+-- stack.
+--
+-- [Computation type:] Computations with implicit access to a
+-- read/write state, with additional operations for pushing the
+-- current state on a stack and later restoring the state from the top
+-- of the stack.
+--
+-- [Binding strategy:] Same as for the usual state monad; the state
+-- and accompanying stack of saved states are threaded through
+-- computations.
+--
+-- [Useful for:] Remembering state while emitting commands for some
+-- system which itself has saveable/restorable state, such as OpenGL
+-- or Cairo.
+--
+-- Simple example:
+--
+-- > ghci> let p = get >>= liftIO . print
+-- > ghci> evalStateStackT (put 2 >> p >> save >> put 3 >> p >> restore >> p) 0
+-- > 2
+-- > 3
+-- > 2
+--
+-----------------------------------------------------------------------------
+
+module Control.Monad.StateStack
+       (
+         -- * The @MonadStateStack@ class
+
+         MonadStateStack(..)
+
+         -- * The @StateStackT@ transformer
+
+       , StateStackT(..), StateStack
+
+         -- * Running @StateStackT@ and @StateStack@ computations
+
+       , runStateStackT, evalStateStackT, execStateStackT
+       , runStateStack,  evalStateStack,  execStateStack
+
+       , liftState
+
+       ) where
+
+import Control.Newtype
+import Data.Monoid
+import Control.Applicative
+import Control.Arrow (second)
+import Control.Monad.Identity
+import qualified Control.Monad.State as St
+import Control.Arrow (first, (&&&))
+
+import Control.Monad.Trans
+import Control.Monad.Trans.Cont
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.List
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Reader (ReaderT)
+import Control.Monad.Trans.State.Lazy as Lazy
+import Control.Monad.Trans.State.Strict as Strict
+import Control.Monad.Trans.Writer.Lazy as Lazy
+import Control.Monad.Trans.Writer.Strict as Strict
+
+import qualified Control.Monad.Cont.Class as CC
+-- import qualified Control.Monad.Error.Class as EC
+import qualified Control.Monad.State.Class as StC
+-- import qualified Control.Monad.Reader.Class as RC
+import qualified Control.Monad.IO.Class as IC
+
+
+------------------------------------------------------------
+--  Implementation
+------------------------------------------------------------
+
+-- | A monad transformer which adds a save/restorable state to an
+--   existing monad.
+newtype StateStackT s m a = StateStackT { unStateStackT :: St.StateT (s,[s]) m a }
+  deriving (Functor, Applicative, Monad, MonadTrans, IC.MonadIO)
+
+instance Newtype (StateStackT s m a) (St.StateT (s,[s]) m a) where
+  pack   = StateStackT
+  unpack = unStateStackT
+
+-- | Class of monads which support a state along with a stack for
+--   saving and restoring states.
+class St.MonadState s m => MonadStateStack s m where
+  save    :: m ()   -- ^ Save the current state on the stack
+  restore :: m ()   -- ^ Restore the top state from the stack
+
+instance Monad m => St.MonadState s (StateStackT s m) where
+  get   = pack $ St.gets fst
+  put s = pack $ (St.modify . first) (const s)
+
+instance Monad m => MonadStateStack s (StateStackT s m) where
+  save = pack $ St.modify (fst &&& uncurry (:))
+  restore = pack . St.modify $ \(cur,hist) ->
+              case hist of
+                []        -> (cur,hist)
+                (r:hist') -> (r,hist')
+
+-- | Run a @StateStackT@ computation from an initial state, resulting
+--   in a computation of the underlying monad which yields the return
+--   value and final state.
+runStateStackT :: Monad m => StateStackT s m a -> s -> m (a, s)
+runStateStackT m s = (liftM . second) fst . flip St.runStateT (s,[]) . unpack $ m
+
+-- | Like 'runStateStackT', but discard the final state.
+evalStateStackT :: Monad m => StateStackT s m a -> s -> m a
+evalStateStackT m s = liftM fst $ runStateStackT m s
+
+-- | Like 'runStateStackT', but discard the return value and yield
+--   only the final state.
+execStateStackT :: Monad m => StateStackT s m a -> s -> m s
+execStateStackT m s = liftM snd $ runStateStackT m s
+
+type StateStack s a = StateStackT s Identity a
+
+-- | Run a @StateStack@ computation from an initial state, resulting
+--   in a pair of the final return value and final state.
+runStateStack :: StateStack s a -> s -> (a,s)
+runStateStack m s = runIdentity $ runStateStackT m s
+
+-- | Like 'runStateStack', but discard the final state.
+evalStateStack :: StateStack s a -> s -> a
+evalStateStack m s = runIdentity $ evalStateStackT m s
+
+-- | Like 'runStateStack', but discard the return value and yield
+--   only the final state.
+execStateStack :: StateStack s a -> s -> s
+execStateStack m s = runIdentity $ execStateStackT m s
+
+-- | @StateT@ computations can always be lifted to @StateStackT@
+--   computations which do not manipulate the state stack.
+liftState :: Monad m => St.StateT s m a -> StateStackT s m a
+liftState st = pack . St.StateT $ \(s,ss) -> (liftM . second) (flip (,) ss) (St.runStateT st s)
+
+------------------------------------------------------------
+--  Applying monad transformers to MonadStateStack monads
+------------------------------------------------------------
+
+instance MonadStateStack s m => MonadStateStack s (ContT r m) where
+  save    = lift save
+  restore = lift restore
+
+instance (Error e, MonadStateStack s m) => MonadStateStack s (ErrorT e m) where
+  save    = lift save
+  restore = lift restore
+
+instance MonadStateStack s m => MonadStateStack s (IdentityT m) where
+  save    = lift save
+  restore = lift restore
+
+instance MonadStateStack s m => MonadStateStack s (ListT m) where
+  save    = lift save
+  restore = lift restore
+
+instance MonadStateStack s m => MonadStateStack s (MaybeT m) where
+  save    = lift save
+  restore = lift restore
+
+instance MonadStateStack s m => MonadStateStack s (ReaderT r m) where
+  save    = lift save
+  restore = lift restore
+
+instance MonadStateStack s m => MonadStateStack s (Lazy.StateT s m) where
+  save    = lift save
+  restore = lift restore
+
+instance MonadStateStack s m => MonadStateStack s (Strict.StateT s m) where
+  save    = lift save
+  restore = lift restore
+
+instance (Monoid w, MonadStateStack s m) => MonadStateStack s (Lazy.WriterT w m) where
+  save    = lift save
+  restore = lift restore
+
+instance (Monoid w, MonadStateStack s m) => MonadStateStack s (Strict.WriterT w m) where
+  save    = lift save
+  restore = lift restore
+
+------------------------------------------------------------
+--  Applying StateStackT to other monads
+------------------------------------------------------------
+
+instance CC.MonadCont m => CC.MonadCont (StateStackT s m) where
+  callCC c = pack $ CC.callCC (unpack . (\k -> c (pack . k)))
+
+{-  -- These require UndecidableInstances =(
+instance EC.MonadError e m => EC.MonadError e (StateStackT s m) where
+  throwError     = lift . EC.throwError
+  catchError m h = pack $ EC.catchError (unpack m) (unpack . h)
+
+instance RC.MonadReader r m => RC.MonadReader r (StateStackT s m) where
+  ask     = lift RC.ask
+  local f = pack . RC.local f . unpack
+-}
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2011, Brent Yorgey
+
+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 Brent Yorgey 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/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/statestack.cabal b/statestack.cabal
new file mode 100644
--- /dev/null
+++ b/statestack.cabal
@@ -0,0 +1,22 @@
+Name:                statestack
+Version:             0.1
+Synopsis:            Simple State-like monad transformer with saveable and restorable state
+Description:         Simple State-like monad transformer where states can be saved to
+                     and restored from an internal stack.
+License:             BSD3
+License-file:        LICENSE
+Author:              Brent Yorgey
+Maintainer:          byorgey@cis.upenn.edu
+Category:            Control
+Build-type:          Simple
+Cabal-version:       >=1.6
+Source-repository head
+  type: darcs
+  location: http://patch-tag.com/r/byorgey/statestack
+
+Library
+  Exposed-modules:     Control.Monad.StateStack
+  Build-depends:       base >= 4.2 && < 4.4,
+                       mtl >= 2.0 && < 2.1,
+                       transformers >= 0.2.2.0 && < 0.3,
+                       newtype >= 0.2 && < 0.3
