[add OnceMap that runs an IO action once for each distinct argument it is passed.
John Meacham <john@repetae.net>**20051013094852] hunk ./Util/Once.hs 4
-module Util.Once(Once, newOnce, runOnce, altOnce) where
+module Util.Once(
+    Once,
+    newOnce,
+    runOnce,
+    altOnce,
hunk ./Util/Once.hs 10
+    OnceMap,
+    newOnceMap,
+    runOnceMap,
+    altOnceMap,
+    onceMapToList,
+    onceMapKeys,
+    onceMapElems
+
+    ) where
+
+import qualified Data.Map as Map
hunk ./Util/Once.hs 57
+-- | run an IO action at most once for each distinct argument
+
+newtype OnceMap a b = OnceMap (IORef (Map.Map a b))
+    deriving(Typeable)
+
+
+newOnceMap :: Ord a => IO (OnceMap a b)
+newOnceMap = do
+    r <- newIORef Map.empty
+    return $ OnceMap r
+
+runOnceMap :: Ord a => OnceMap a b -> a -> IO b -> IO b
+runOnceMap (OnceMap r) x act = do
+    m <- readIORef r
+    case Map.lookup x m of
+        Just y -> return y
+        Nothing -> do
+            y <- act
+            modifyIORef r (Map.insert x y)
+            return y
+
+altOnceMap :: Ord a => OnceMap a () -> a -> IO b -> IO b -> IO b
+altOnceMap (OnceMap ref) x first after = do
+    m <- readIORef ref
+    case Map.member x m of
+        True -> after
+        False -> do
+            modifyIORef ref (Map.insert x ())
+            first
+
+onceMapToList :: OnceMap a b -> IO [(a,b)]
+onceMapToList (OnceMap ref) = do
+    m <- readIORef ref
+    return $ Map.toList m
+
+onceMapKeys :: OnceMap a b -> IO [a]
+onceMapKeys (OnceMap ref) = do
+    m <- readIORef ref
+    return $ Map.keys m
+
+onceMapElems :: OnceMap a b -> IO [b]
+onceMapElems (OnceMap ref) = do
+    m <- readIORef ref
+    return $ Map.elems m