On Thursday 28 August 2008 12:26:27 pm Adrian Hey wrote: > As I've pointed out several times already you can find simple examples > in the standard haskell libs. So far nobody has accepted my challenge to > re-implement any of these "competantly" (I.E. avoiding the use of global > variables). > > Why don't you try it with Data.Unique and find out :-)
Here's a first pass: -- snip -- {-# LANGUAGE Rank2Types, GeneralizedNewtypeDeriving #-} module Unique where import Control.Monad.Reader import Control.Monad.Trans import Control.Concurrent.MVar -- Give Uniques a phantom region parameter, so that you can't accidentally -- compare Uniques from two different uniqueness sources. newtype Unique r = Unique Integer deriving Eq newtype U r a = U { unU :: ReaderT (MVar Integer) IO a } deriving (Functor, Monad, MonadIO) -- Higher rank type for region consistency runU :: (forall r. U r a) -> IO a runU m = newMVar 0 >>= runReaderT (unU m) newUnique :: U r (Unique r) newUnique = U (do source <- ask val <- lift $ takeMVar source let next = val + 1 lift $ putMVar source next return $ Unique next) -- hashUnique omitted -- snip -- It's possible that multiple unique sources can exist in a program with this implementation, but because of the region parameter, the fact that a Unique may not be "globally" unique shouldn't be a problem. If your whole program needs arbitrary access to unique values, then I suppose something like: main = runU realMain realMain :: U r () realMain = ... is in order. Insert standard complaints about this implementation requiring liftIO all over the place if you actually want to do other I/O stuff inside the U monad. You could also make a version that extracts to STM, or even a pure version if you don't need unique values across multiple threads. -- Dan _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe