How to make Claessen's Refs Ord-able?

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

Hi, Have you tried the following: {-# NOINLINE refWInt #-} ? /Josef On Tue, 19 Mar 2002, Mike Gunter wrote:
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 _______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

A while back I asked how to make the Ref's from Koen Clasessen's PhD thesis Ord-able for the purpose of making them keys for efficient finite maps. Koen quickly responded with a clever implementation which attaches the values to the keys. While I don't rule out eventually making use of it, this solution has the drawback of requiring lookups in the finite map to be inside the ST or IO monad. Josef Svenningsson asked if I had tried adding {-# NOINLINE refWInt #-} I had (quite hopefully.) It doesn't work. After fiddling a bit to get a sense of what works and what doesn't, I tried: {-# INLINE refWInt #-} . This does the trick! I've included the working code (which differs from that of my original message only by the addition of the INLINE directive) below. My question to the GHC implementors is: what's going on here? Can you give us (at least Josef and I are confused) any help in predicting how unsafePerformIO will behave? thanks to all, mike
import IOExts ( IORef, newIORef, readIORef, writeIORef, unsafePerformIO )
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)
{-# INLINE refWInt #-} 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
things only work with the INLINE directive. Without it, I get: (RefWInt (0,"a"),RefWInt (1,"b"),RefWInt (1,"b")) (RefWInt (0,"a"),RefWInt (1,"b"),RefWInt (1,"b"))

| I'd like to extend the Ref type for observable sharing | of Koen Claessen's Ph.D. thesis: to make it possible | for the Refs to be the keys for efficient finite maps. I did this in the Lava implementation. The Ref module I attach works in Hugs and GHC. /Koen.
participants (3)
-
Josef Svenningsson
-
Koen Claessen
-
Mike Gunter