diff --git a/Data/QuotientRef.hs b/Data/QuotientRef.hs
new file mode 100644
--- /dev/null
+++ b/Data/QuotientRef.hs
@@ -0,0 +1,88 @@
+----------------------------------------
+-- |
+-- Module    : Data.QuotientRef
+-- Copyright : (c) Luke Palmer 2008
+-- License   : BSD3
+--
+-- Maintainer : Luke Palmer <lrpalmer@gmail.com>
+-- Stability : experimental
+--
+-- A Quotient Reference is a reference cell that needs two values to
+-- dereference.  In a way it is a two-dimensional table indexed by references.
+-- The trick is that if a cell is indexed by @a@ and @b@, then if /either/
+-- @a@ or @b@ gets cleaned up by the garbage collector, then so does the
+-- cell, because it would not be able to be accessed anymore.
+--
+-- There are two different types of indices, "LeftRef" and "RightRef".  You
+-- need one of each, of the same type, to access a cell.
+--
+-- The name comes from the idea that the product of two indices is a reference,
+-- so each index is a quotient.
+--
+-- Example usage:
+--
+-- > do
+-- >   l_1 <- newLeft
+-- >   l_2 <- newLeft
+-- >   r_1 <- newRight
+-- >   r_2 <- newRight
+-- >   write l_1 r_1 "Foo"
+-- >   write l_2 r_1 "Bar"
+-- >   print =<< read l_1 r_1  -- Just "Foo"
+-- >   print =<< read l_1 r_2  -- Nothing
+-- >   print =<< read l_2 r_1  -- Just "Bar"
+-- >   print =<< read l_2 r_2  -- Nothing
+-- 
+module Data.QuotientRef 
+    ( LeftRef, RightRef
+    , newLeft, newRight
+    , read, write
+    )
+where
+
+import Prelude hiding (read)
+import qualified Data.HashTable as Hash
+import Data.Unique
+import Control.Applicative
+import Control.Exception
+import Control.Monad
+import System.Mem.Weak
+
+-- | The left half of a reference cell.  Combine this with a "RightRef" to
+-- access a cell.
+newtype LeftRef a
+    = LeftRef (Hash.HashTable Unique a)
+
+-- RightRef is data rather than newtype, so we have something real to make 
+-- a weak reference from.
+
+-- | The right half of a reference cell.  Combine this with a "LeftRef" to
+-- access a cell.
+data RightRef a
+    = RightRef Unique
+
+
+newLeft :: IO (LeftRef a)
+newLeft = LeftRef <$> Hash.new (==) (fromIntegral . hashUnique)
+
+newRight :: IO (RightRef a)
+newRight = RightRef <$> newUnique
+
+-- | Combine the two halves of a reference and return the result if
+-- it exists.
+read :: LeftRef a -> RightRef a -> IO (Maybe a)
+read (LeftRef hash) (RightRef ident) = do
+    Hash.lookup hash ident
+
+-- | Combine the two halves of a reference and write a value to the
+-- product.
+write :: LeftRef a -> RightRef a -> a -> IO ()
+write (LeftRef hash) right@(RightRef ident) val = block $ do
+    existed <- Hash.update hash ident val
+    unless existed $ do
+        hashW <- mkWeakPtr hash Nothing
+        addFinalizer right $ do
+            h <- deRefWeak hashW
+            case h of
+                Nothing -> return ()
+                Just h' -> Hash.delete h' ident
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
diff --git a/data-quotientref.cabal b/data-quotientref.cabal
new file mode 100644
--- /dev/null
+++ b/data-quotientref.cabal
@@ -0,0 +1,14 @@
+Name: data-quotientref
+Description:
+    Reference cells that need two independent indices to be accessed.
+Version: 0.1
+Stability: experimental
+Synopsis: Reference cells that need two independent indices to be accessed.
+License: BSD3
+Category: Data
+Author: Luke Palmer
+Maintainer: lrpalmer@gmail.com
+Build-Type: Simple
+Build-Depends: base
+Exposed-Modules: Data.QuotientRef
+Extensions: 
