RE: unsafePtrCompare, anybody?

I'm writing an atom table for a compiler/interpreter, and it would be really nice to use unsafePtrLT to implement tree-based finite maps.
For clarification, my atom table consists of these three functions:
mkAtom :: String -> IO Atom show :: Atom -> String (==) :: Atom -> Atom -> Bool
such that mkAtom s >>= (return . show) == return s and mkAtom . show == return and atom == atom' <=> show atom == show atom'
mkAtom looks up each string in a table stored in an global variable, and returns the atom stored in the table if it is there. Otherwise, it makes the string into an atom, inserts the atom into the table, and returns this new atom.
The point of all of this is that now string equality, when strings are made into atoms, is just pointer equality, which is available as IOExts.unsafePtrEq.
You might want to check out GHC's FastString module, which does essentially this. We use an explicit hash table, and each FastString has a unique Id for fast comparison. To solve your immediate problem, you could also take a look at the StableName library, which lets you map any old Haskell value on to an Int so you can build finite maps etc. (we use StableNames to build memo tables). There's a small garbage collector overhead for this, though.
Of course, the misuses of unsafePtrEq aren't nearly as heinous as those of unsafePtrCompare. On the other hand, it might be next to impossible to effectively use unsafePtrCompare in cases that it isn't completely safe to use, whereas there are plently of situations where unsafePtrEq is semi-safe to use.
I can't think of a way to use unsafePtrCompare safely :-) The relative ordering of objects isn't guaranteed to be stable under GC. Cheers, Simon

I can't think of a way to use unsafePtrCompare safely :-) The relative ordering of objects isn't guaranteed to be stable under GC.
Cheers, Simon
Doh, that would throw a monkey wrench into things, wouldn't it? I know of compacting GC algorithms, but I didn't consider that GHC might be using one. At least I am now more enlightened on the inner workings of the magic beast... I've considered many of the other implementation options, but as it isn't essential to the working of the compiler, it hasn't been a priority yet. It simply struck me that this would be a particularly quick and easy way to implement reasonably good atom tables, only requiring a newtype declaration and a few very simple function definitions. Thanks to Simon for saving me from reinventing the wheel. The libraries mentioned here should prove to be quite useful. One's intuition would suggest that you could be safely implement mkAtom without wrapping it in a IO monad. After all, at least at a abstract level, an atom table is referentially transparent. The library documentation says that lack of side effects and environmental independance is sufficent to order for uses of unsafePerformIO to be safe. Is there a exact (or at least better) criterion for safety? "unsafePerformIO" is used in the implementation of mkFastString, so how is it's side effects "safe". I experimented with unsafePerformIO with my Atom table, but I could not get tthe code to work properly. best, leon
participants (2)
-
Leon Smith
-
Simon Marlow