diff --git a/COPYING b/COPYING
new file mode 100644
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2008, Ivan Tomac
+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 the author nor the names of the 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/IOR.cabal b/IOR.cabal
new file mode 100644
--- /dev/null
+++ b/IOR.cabal
@@ -0,0 +1,25 @@
+name:               IOR
+version:            0.1
+synopsis:           Region based resource management for the IO monad.
+description:        IOR monad is a wrapper around IO that allows region based
+                    resource management.
+category:           System, Monadic Regions
+cabal-version:   >= 1.2
+license:            BSD3
+license-file:       COPYING
+author:             Ivan Tomac
+maintainer:         tomac `at` pacific `dot` net `dot` au
+stability:          experimental
+build-type:         Simple
+data-files:         README
+extra-source-files: src/Example.hs
+                    src/Test.hs
+
+library
+  build-depends:        base, mtl
+  ghc-options:          -Wall
+  hs-source-dirs:       src
+  exposed-modules:      Data.IORRef
+                        System.IOR
+                        System.IOR.Resource
+  other-modules:        System.IOR.Internal
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,24 @@
+To build the library type
+
+    runhaskell Setup.lhs configure
+    runhaskell Setup.lhs build
+    runhaskell Setup.lhs haddock    # optional
+    runhaskell Setup.lhs install
+
+There are a few tests and examples in the src directory.
+
+TODOs:
+-----
+
+It may be possible (and worthwhile) to write a more general region monad that
+is not tied to IO. I've had a brief look into this but right now I can't find
+a clean and consistent way to abstract mutable references for different
+monads.
+
+It would also be nice to provide all the functions found in System.IO ideally
+in such a way so the functions can be used with either Strings, ByteStrings or
+something else.
+I can't think of a clean way to do this either. Any suggestions would be
+welcome.
+
+Ivan Tomac 25/05/2008
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/src/Data/IORRef.hs b/src/Data/IORRef.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/IORRef.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-------------------------------------------------------------------------------
+-- |
+-- Module       : Data.IORRef
+-- Copyright    : (c) Ivan Tomac 2008
+-- License      : BSD3
+--
+-- Maintainer   : tomac `at` pacific `dot` net `dot` au
+-- Stability    : experimental
+--
+-- Mutable references in the IOR monad.
+--
+-------------------------------------------------------------------------------
+
+module Data.IORRef (
+    IORRef
+
+  , newIORRef
+  , readIORRef
+  , writeIORRef
+  , modifyIORRef
+) where
+
+import Control.Monad.Trans
+
+import Data.Generics
+import Data.IORef
+
+import System.IOR
+
+-- | A value of type @'IORRef' r a@ is a mutable variable in region @r@,
+-- containing a value of type @a@.
+
+newtype IORRef r a
+  = IORRef { unIORRef :: IORef a }
+    deriving (Data, Eq, Typeable)
+
+-- | Create a new 'IORRef' in region @r@.
+
+newIORRef :: a -> IOR r rs (IORRef r a)
+newIORRef = liftIO . fmap IORRef . newIORef
+
+-- | Read the value of an 'IORRef'.
+
+readIORRef :: RElem r' rs => IORRef r' a -> IOR r rs a 
+readIORRef = liftIO . readIORef . unIORRef
+
+-- | Write a new value into an 'IORRef'.
+
+writeIORRef :: RElem r' rs => IORRef r' a -> a -> IOR r rs ()
+writeIORRef = (liftIO .) . writeIORef . unIORRef
+
+-- | Mutate the contents of an 'IORRef'.
+
+modifyIORRef :: RElem r' rs => IORRef r' a -> (a -> a) -> IOR r rs ()
+modifyIORRef = (liftIO .) . modifyIORef . unIORRef
diff --git a/src/Example.hs b/src/Example.hs
new file mode 100644
--- /dev/null
+++ b/src/Example.hs
@@ -0,0 +1,60 @@
+module Main where
+
+import Control.Monad.Trans
+
+import System.IOR
+import System.IOR.Resource
+
+-------------------------------------------------------------------------------
+
+newtype P
+  = P String
+
+openP  :: String -> IO P
+closeP :: P -> IO ()
+writeP :: P -> String -> IO ()
+
+openP s = do
+    putStrLn ("opening " ++ s)
+    return   (P s)
+
+closeP (P s) =
+    putStrLn ("closing " ++ s)
+
+writeP (P s) msg =
+    putStrLn ("writing " ++ msg ++ " to " ++ s)
+
+-------------------------------------------------------------------------------
+
+newtype R r
+  = R (Resource r P)
+
+openR  :: String -> IOR r rs (R r)
+closeR :: RElem r' rs => R r' -> IOR r rs ()
+writeR :: RElem r' rs => R r' -> String -> IOR r rs ()
+
+openR s = do
+    p <- liftIO (openP s)
+    fmap R (manage p closeP)
+
+closeR (R r) =
+    release r
+
+writeR (R r) msg =
+    liftIO (writeP (getResource r) msg)
+
+-------------------------------------------------------------------------------
+
+main :: IO ()
+main = runIOR $ do
+    r     <- getIORTag
+    res1a <- openR "res1a"
+    res1b <- openR "res1b"
+    newIOR $ do
+        res2a <- openR "res2a"
+        res1c <- withIORTag r $ openR "res1c"
+        writeR res1b "msg1"
+        closeR res1b
+        writeR res1c "msg2"
+        writeR res2a "msg3"
+    writeR res1a "msg4"
diff --git a/src/System/IOR.hs b/src/System/IOR.hs
new file mode 100644
--- /dev/null
+++ b/src/System/IOR.hs
@@ -0,0 +1,35 @@
+-------------------------------------------------------------------------------
+-- |
+-- Module       : System.IOR
+-- Copyright    : (c) Ivan Tomac 2008
+-- License      : BSD3
+--
+-- Maintainer   : tomac `at` pacific `dot` net `dot` au
+-- Stability    : experimental
+--
+-- Region based resource management for the IO monad.
+-- Based on the ideas and code from
+-- <http://okmij.org/ftp/Haskell/regions.html>
+--
+-------------------------------------------------------------------------------
+
+module System.IOR (
+    -- * Type Classes and Auxiliary Data Types
+    RElem
+  , RCons
+  , RNil
+
+    -- * IOR Monad
+  , IOR
+
+  , runIOR
+  , newIOR
+
+    -- * Region Tags
+  , IORTag
+
+  , getIORTag
+  , withIORTag
+) where
+
+import System.IOR.Internal
diff --git a/src/System/IOR/Internal.hs b/src/System/IOR/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/System/IOR/Internal.hs
@@ -0,0 +1,175 @@
+{-# LANGUAGE DeriveDataTypeable
+           , EmptyDataDecls
+           , ExistentialQuantification
+           , FlexibleInstances
+           , IncoherentInstances
+           , MultiParamTypeClasses
+           , PolymorphicComponents
+           , TypeSynonymInstances
+  #-}
+
+-------------------------------------------------------------------------------
+-- |
+-- Module       : System.IOR.Internal
+-- Copyright    : (c) Ivan Tomac 2008
+-- License      : BSD3
+--
+-- Maintainer   : tomac `at` pacific `dot` net `dot` au
+-- Stability    : experimental
+--
+-- IOR monad internals.
+--
+-------------------------------------------------------------------------------
+
+module System.IOR.Internal (
+    RElem
+  , RCons
+  , RNil
+
+  , IOR (..)
+
+  , runIOR
+  , newIOR
+
+  , IORTag (..)
+
+  , getIORTag
+  , withIORTag
+
+  , Resource  (..)
+  , Resource' (..)
+) where
+
+import Control.Applicative
+import Control.Monad.Error
+import Control.Monad.Trans
+
+import Data.Generics
+import Data.IORef
+
+import System.IO.Error
+
+class RElem r rs
+
+data RCons r rs
+data RNil
+
+instance               RElem r (RCons r  rs)
+instance RElem r rs => RElem r (RCons r' rs)
+
+-- | 'IO' monad with support for region based resource allocation.
+-- A computation of type @'IOR' r rs a@ wraps an action of type @'IO' a@
+-- where @r@ is an unconstrained type variable indicating the current region
+-- and @rs@ is a collection of all accessible regions within the computation.
+--
+-- 'IO' actions can be lifted into the 'IOR' monad using 'liftIO'.
+-- It is safe to throw 'IOError'-s inside an 'IOR' computation.
+-- Allocated resources will be released on exit automatically.
+
+data IOR r rs a
+  = IOR { unIOR :: IORTag r -> IO a }
+    deriving (Data, Typeable)
+
+instance Monad (IOR r rs) where
+    return  = IOR . const . return
+    m >>  n = IOR $ liftA2 (>>)  (unIOR m) (unIOR n)
+    m >>= f = IOR $ liftA2 (>>=) (unIOR m) (flip $ unIOR . f)
+
+    {-# INLINE return #-}
+    {-# INLINE (>>)   #-}
+    {-# INLINE (>>=)  #-}
+
+instance Functor (IOR r rs) where
+    fmap f m = IOR $ fmap f . unIOR m
+    {-# INLINE fmap #-}
+
+instance Applicative (IOR r rs) where
+    pure  = return
+    (<*>) = ap
+
+instance MonadIO (IOR r rs) where
+    liftIO = IOR . const
+    {-# INLINE liftIO #-}
+
+instance MonadFix (IOR r rs) where
+    mfix f = IOR $ mfix . flip (unIOR . f)
+    {-# INLINE mfix #-}
+
+instance MonadError IOError (IOR r rs) where
+    throwError = liftIO . throwError
+
+    catchError m handler = IOR catchError'
+        where
+            catchError' = liftA2 catchError (unIOR m) handler'
+            handler'    = flip (unIOR . handler)
+
+run :: IOR r rs a -> IO a
+run m = do
+    ref <- newIORef (0, [])
+    e   <- try $ unIOR m $ IORTag ref
+    readIORef ref >>= mapM_ finalizeRes . snd
+    either throwError return e
+    where
+        finalizeRes (Resource' r) = finalizer r
+
+-- | Create the initial region, @r@, and run the computation returning a
+-- value of type @'IO' a@.
+
+runIOR :: IOR r (RCons r RNil) a -> IO a
+runIOR = run
+
+-- | Create a new region @r'@ inside @r@. All resources allocated in
+-- @r'@ are only accessible from @r'@ and any of it's child regions.
+-- On exit from the region, all allocated resources are automatically
+-- released.
+
+newIOR :: IOR r' (RCons r' rs) a -> IOR r rs a
+newIOR = liftIO . run
+
+type IdTag = Integer
+
+-- | A region tag @'IORTag' r@ captures state of the region @r@ including all
+-- currently allocated resources in @r@.
+
+newtype IORTag r
+  = IORTag { unIORTag :: IORef (IdTag, [Resource' r]) }
+    deriving (Data, Eq, Typeable)
+
+-- | Get the current region's tag.
+
+getIORTag :: IOR r rs (IORTag r)
+getIORTag = IOR return
+
+-- | Temporarily change the current region from @r@ to @r'@. This allows
+-- allocation of resources in @r'@.
+--
+-- @r'@ has to be one of the parent regions of @r@.
+
+withIORTag :: RElem r' rs => IORTag r' -> IOR r' rs a -> IOR r rs a
+withIORTag = (liftIO .) . flip unIOR
+
+-- | @'Resource' r a@ wraps a resource of type @a@ so it can be managed
+-- inside region @r@ and automatically released upon exit from @r@.
+
+data Resource r a
+  = Resource {
+      -- | Extract @a@ from the 'Resource' wrapper.
+        getResource :: a
+      -- | Tag that uniquely identifies the resource in the current region.
+      , idTag       :: IdTag
+      -- | Reference to region state.
+      , tagRef      :: IORef (IdTag, [Resource' r])
+      -- | Finalizer for the resource.
+      , finalizer   :: IO ()
+    }
+    deriving (Data, Typeable)
+
+instance Eq (Resource r a) where
+    r1 == r2 = idTag r1 == idTag r2
+
+data Resource' r
+  = forall a. Resource' {-# UNPACK #-} !(Resource r a)
+    deriving Typeable
+
+instance Eq (Resource' r) where
+    Resource' r1 == Resource' r2 = idTag r1 == idTag r2
diff --git a/src/System/IOR/Resource.hs b/src/System/IOR/Resource.hs
new file mode 100644
--- /dev/null
+++ b/src/System/IOR/Resource.hs
@@ -0,0 +1,58 @@
+-------------------------------------------------------------------------------
+-- |
+-- Module       : System.IOR.Resource
+-- Copyright    : (c) Ivan Tomac 2008
+-- License      : BSD3
+--
+-- Maintainer   : tomac `at` pacific `dot` net `dot` au
+-- Stability    : experimental
+--
+-- Resource management in the IOR monad.
+--
+-------------------------------------------------------------------------------
+
+module System.IOR.Resource (
+    Resource
+  , getResource
+
+  , manage
+  , release
+) where
+
+import Control.Arrow
+import Control.Monad.Trans
+
+import Data.IORef
+import Data.List
+
+import System.IOR.Internal
+
+-- | @'manage' a f@ will create a new 'Resource' wrapper around the
+-- value of type @a@ in region @r@, given a finalizer @f@.
+-- Each finalizer is guaranteed to automatically be called upon exit from
+-- the region.
+-- Finalizers are called in the last in, first out fashion. So the finalizer
+-- of the very last resource allocated will be the first to get called.
+--
+-- Note that finalizers must not throw any errors. Failing to ensure that
+-- all errors in a finalizer are handled may result in a resource leak.
+
+manage :: a -> (a -> IO ()) -> IOR r rs (Resource r a)
+manage a f = IOR (new . unIORTag)
+    where
+        new ref = do
+            (c, rs) <- readIORef ref
+            let r = Resource a c ref (f a)
+            writeIORef ref (succ c, Resource' r : rs)
+            return r
+
+-- | @'release' res@ is used to force the resource @res@ to be
+-- released immediately. Finalizer for @res@ will be called and removed
+-- from the stack of finalizers in region @r'@.
+
+release :: RElem r' rs => Resource r' a -> IOR r rs ()
+release r = liftIO $ do
+    readIORef ref >>= writeIORef ref . (id *** delete (Resource' r))
+    finalizer r
+    where
+        ref = tagRef r
diff --git a/src/Test.hs b/src/Test.hs
new file mode 100644
--- /dev/null
+++ b/src/Test.hs
@@ -0,0 +1,44 @@
+module Main where
+
+import Control.Applicative
+import Control.Monad
+
+import Data.IORRef
+
+import System.IOR
+
+gpair :: (RElem r0 rs, RElem r1 rs)
+      => IORRef r0 a -> IORRef r1 b -> IOR r rs (IORRef r (a, b))
+
+test1 :: IO ()
+test2 :: IO ()
+test3 :: IO ()
+main  :: IO ()
+
+gpair v w = liftA2 (,) (readIORRef v) (readIORRef w) >>= newIORRef
+
+test1 = (print =<<) $ runIOR $ do
+    r1 <- getIORTag
+    a  <- newIORRef 1
+    c  <- newIOR $ do
+        v  <- readIORRef a
+        b  <- newIORRef 2
+        v' <- readIORRef b
+        withIORTag r1 (newIORRef $ v + v')
+    readIORRef c
+
+test2 = (print =<<) $ runIOR $ do
+    v <- newIORRef 1
+    newIOR $ do
+        w  <- newIORRef 2
+        liftA2 (,)
+               (gpair v w >>= readIORRef)
+               (gpair w v >>= readIORRef)
+
+test3 = (print =<<) $ runIOR $
+    newIOR (newIORRef 1 >>= join gpair >>= readIORRef)
+
+main = do
+    test1
+    test2
+    test3
