data-quotientref (empty) → 0.1
raw patch · 3 files changed
+106/−0 lines, 3 filesdep +basesetup-changed
Dependencies added: base
Files
- Data/QuotientRef.hs +88/−0
- Setup.lhs +4/−0
- data-quotientref.cabal +14/−0
+ Data/QuotientRef.hs view
@@ -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
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ data-quotientref.cabal view
@@ -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: