How to make Claessen's Refs Ord-able?

Mike Gunter m@ryangunter.com
Tue, 19 Mar 2002 15:56:57 -0800


I'd like to extend the Ref type for observable sharing of Koen Claessen's
Ph.D. thesis:

> import IOExts     ( IORef, newIORef, readIORef, writeIORef, unsafePerformIO )
>
> newtype Ref a = MkRef (IORef a)
> 
> ref :: a -> Ref a
> ref x = MkRef (unsafePerformIO (newIORef x))
> 
> deref :: Ref a -> a
> deref (MkRef r) = unsafePerformIO (readIORef r)
> 
> (<==>) :: Ref a -> Ref a -> Bool
> (MkRef ref1) <==> (MkRef ref2)    = ref1 == ref2

to make it possible for the Refs to be the keys for efficient finite maps.
I.e. I want something with at least an efficient Ord-like compare and maybe
also a hash function.

The closest I've got is:

> type    UniqTy    = Integer
> newtype RefWInt a = RefWInt (UniqTy, a)   deriving (Show)
>
> curUniqInt    :: IORef UniqTy
> curUniqInt    = unsafePerformIO (newIORef 0)
> newRef a  = do
>   v <- readIORef curUniqInt
>   writeIORef curUniqInt (v + 1)
>   return (v, a)
> 
> refWInt x = RefWInt (unsafePerformIO (newRef x))

which works properly for this program alone:

> tri_1 = (a, b, b1)
>   where a  = refWInt "a"
>     b  = refWInt "b"
>     b1 = refWInt "b"

yielding (RefWInt (0,"a"),RefWInt (1,"b"),RefWInt (2,"b")).  

But if I add another copy of the same definition:

> tri_2 = (a, b, b1)
>   where a  = refWInt "a"
>     b  = refWInt "b"
>     b1 = refWInt "b"


and use it by uncommenting the second line here:

> main =   print tri_1
>  --   >> print tri_2

I get:

  (RefWInt (0,"a"),RefWInt (1,"b"),RefWInt (1,"b"))
  (RefWInt (0,"a"),RefWInt (1,"b"),RefWInt (1,"b"))

with ghc.  (I get the desired

  (RefWInt (0,"a"),RefWInt (1,"b"),RefWInt (2,"b"))
  (RefWInt (3,"a"),RefWInt (4,"b"),RefWInt (5,"b"))

with ghci.)


Can I write code to always get the desired behavior?  How?

        thanks,
        mike