Suggestions for simulating Object ID

Hello all, Can some one please suggest something on simulating some sort of "object-Ids" in Haskell? I mean, something like the following relation will hold:
a1 == a2 = (objectID a1) == (objectID a2)
Currently I have something like
import Data.Hash import qualified Data.ByteString.Char8 as B
newtype UniqueID = UniqueID (Hash, B.ByteString)
I have a type class called Identifiable, the instances of which are supposed to give a unqiue bytestring representation of the instance which can be arbitrarily long but should satisfy the condition mentioned earlier.
class Identifiable a where instanceID :: a -> B.ByteString
and finally, the required funtion objectID is defined as :
objectID :: (Hashable a, Identifiable a) => a -> UniqueID objectID a1 = UniqueID (hash a1, instanceID a1)
while comparing object Ids, I compare the hash values first (which can be faster for arbitrary values). Only if they are equal then I compare the instanceIDs and count on laziness for avoiding the construction of the bytestrings where they are not needed. Can you please suggest a better approach? I also toyed with the idea of storing all the data 'objects' in an array and use the index as the identifier but the trouble is I am not aware of all the number of instances before hand under all the circumstances. Many thanks Hemanth K

On Tue, Jun 30, 2009 at 03:25:26PM +0530, Hemanth Kapila wrote:
Can some one please suggest something on simulating some sort of "object-Ids" in Haskell?
Data.Unique[1]? [1] http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Unique... -- Felipe.

Thank you. It looks perfect for now.
Just that I can create it only inside an IO
(newUnique is of type IO Unique)
Perhaps it involves some magic with random numbers or system time.
Can't we come up with something like this staying within the limits of purity?
Thanks
Hemanth
On 6/30/09, Felipe Lessa
On Tue, Jun 30, 2009 at 03:25:26PM +0530, Hemanth Kapila wrote:
Can some one please suggest something on simulating some sort of "object-Ids" in Haskell?
Data.Unique[1]?
[1] http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Unique...
-- Felipe. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Tue, Jun 30, 2009 at 07:57:07PM +0530, Hemanth Kapila wrote:
Can't we come up with something like this staying within the limits of purity?
No, because that would break referential transparency :(. I.e., it would be possible to distinguish things that should be "equal", such as '3' from '1+2'. -- Felipe.

On Tue, Jun 30, 2009 at 9:16 AM, Felipe Lessa
On Tue, Jun 30, 2009 at 07:57:07PM +0530, Hemanth Kapila wrote:
Can't we come up with something like this staying within the limits of purity?
No, because that would break referential transparency :(. I.e., it would be possible to distinguish things that should be "equal", such as '3' from '1+2'.
This isn't entirely true; you can do something like this:
newtype Unique = U Integer deriving (Eq) newtype UniqueM a = UniqueM (State Integer a) deriving Monad runUniqueM (UniqueM a) = evalState a 0
newUnique = UniqueM $ do u <- get put $! (u+1) return (U u)
Also, if you are willing to go inside of IO/ST for some bits of your code, you can use some tricks with unsafeInterleaveIO/ST to create data structures with unique ids that only get created if they are used; this allows creating infinite data structures and still keeping object ID. The returned data structure is still pure if the "U" constructor is hidden; all we can do is compare uniques for equality. You can relax this slightly by adding an Ord derivation; this technically allows you to observe creation order for the uniques which is wrong, but it's quite useful to be able to use Uniques as map keys.
data Tree a = Tree a (Tree a) (Tree a) infTree :: IO (Tree Unique) infTree = do r <- newIORef 0 mkTree r mkTree :: IORef Integer -> IO (Tree Unique) mkTree r = unsafeInterleaveIO $ do v <- readIORef r writeIORef r $! (v+1) l <- mkTree r r <- mkTree r return (Tree (U v) l r)
I believe GHC uses this technique internally. -- ryan

This is implemented in Data.Supply
(http://hackage.haskell.org/package/value-supply). The difference is:
Data.Unique is *globally* unique, while Data.Supply is only locally
unique. I ran into problems with this when writing tests.
2009/6/30 Ryan Ingram
On Tue, Jun 30, 2009 at 9:16 AM, Felipe Lessa
wrote: On Tue, Jun 30, 2009 at 07:57:07PM +0530, Hemanth Kapila wrote:
Can't we come up with something like this staying within the limits of purity?
No, because that would break referential transparency :(. I.e., it would be possible to distinguish things that should be "equal", such as '3' from '1+2'.
This isn't entirely true; you can do something like this:
newtype Unique = U Integer deriving (Eq) newtype UniqueM a = UniqueM (State Integer a) deriving Monad runUniqueM (UniqueM a) = evalState a 0
newUnique = UniqueM $ do u <- get put $! (u+1) return (U u)
Also, if you are willing to go inside of IO/ST for some bits of your code, you can use some tricks with unsafeInterleaveIO/ST to create data structures with unique ids that only get created if they are used; this allows creating infinite data structures and still keeping object ID. The returned data structure is still pure if the "U" constructor is hidden; all we can do is compare uniques for equality. You can relax this slightly by adding an Ord derivation; this technically allows you to observe creation order for the uniques which is wrong, but it's quite useful to be able to use Uniques as map keys.
data Tree a = Tree a (Tree a) (Tree a) infTree :: IO (Tree Unique) infTree = do r <- newIORef 0 mkTree r mkTree :: IORef Integer -> IO (Tree Unique) mkTree r = unsafeInterleaveIO $ do v <- readIORef r writeIORef r $! (v+1) l <- mkTree r r <- mkTree r return (Tree (U v) l r)
I believe GHC uses this technique internally.
-- ryan _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Push the envelope. Watch it bend.

Hi, On 30.06.2009, at 11:55, Hemanth Kapila wrote:
Can some one please suggest something on simulating some sort of "object-Ids" in Haskell?
I mean, something like the following relation will hold:
a1 == a2 = (objectID a1) == (objectID a2)
I am not quite sure but perhaps Stable Names are also interesting for you. They only provide the following: mkStableName x == mkStableName y => x == y http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-Mem-Stable... "Stable names are a way of performing fast (O(1)), not-quite-exact comparison between objects. Stable names solve the following problem: suppose you want to build a hash table with Haskell objects as keys, but you want to use pointer equality for comparison; maybe because the keys are large and hashing would be slow, or perhaps because the keys are infinite in size. We can't build a hash table using the address of the object as the key, because objects get moved around by the garbage collector, meaning a re-hash would be necessary after every garbage collection." Cheers, Jan
participants (5)
-
Felipe Lessa
-
Hemanth Kapila
-
Jan Christiansen
-
Ryan Ingram
-
Thomas Schilling