@@ -1,44 +1,41 @@
1−module Data.Unique
2− ( newUnique
3− , Unique()
4− , Uniq()
5− ) where
6−
7−import Control.Monad.Eff
8−
9−foreign import data Uniq :: !
10−
11−newtype Unique = Unique String
12−
13−foreign import newUnique """
14− var newUnique = (function() {
15− var MAX_SAFE_INTEGER = 9007199254740991;
16− var uniqueSource = [];
17− function iter(i) {
18− if(uniqueSource.length === i) {
19− for(var j = 0; j < i; ++j) uniqueSource[j] = 0;
20− uniqueSource[i] = 1;
21− } else {
22− if(uniqueSource[i] === MAX_SAFE_INTEGER) {
23− uniqueSource[i] = 0;
24− iter(i + 1);
25− } else {
26− uniqueSource[i]++;
27− }
28− }
29− };
30− return function() {
31− iter(0);
32− return uniqueSource.length === 1 ? (uniqueSource[0] + "") : uniqueSource.join(',');
33− };
34− })();""" :: forall e. Eff (uniq :: Uniq | e) Unique
35−
36−instance showUnique :: Show Unique where
37− show (Unique a) = a
38−
39−instance eqUnique :: Eq Unique where
40− (==) (Unique a) (Unique b) = a == b
41− (/=) (Unique a) (Unique b) = a /= b
42−
43−instance ordUnique :: Ord Unique where
44− compare (Unique a) (Unique b) = compare a b
1+module Data.Unique (Unique, hashUnique, newUnique) where
2+
3+import Prelude hiding (zero)
4+
5+import Effect (Effect)
6+import Effect.Ref (Ref)
7+import Effect.Ref as Ref
8+import Effect.Unsafe (unsafePerformEffect)
9+
10+-- | An abstract unique object. Objects of type `Unique` may be compared for
11+-- | equality and ordering and hashed into `Int`.
12+foreign import data Unique :: Type
13+
14+foreign import eqImpl :: Unique -> Unique -> Boolean
15+
16+instance Eq Unique where
17+ eq = eqImpl
18+
19+foreign import ordImpl :: Ordering -> Ordering -> Ordering -> Unique -> Unique -> Ordering
20+
21+instance Ord Unique where
22+ compare = ordImpl LT EQ GT
23+
24+foreign import addOne :: Unique -> Unique
25+
26+foreign import zero :: Unique
27+
28+-- | Hashes a `Unique` into an `Int`. Two `Unique`s may hash to the same value,
29+-- | although in practice this is unlikely. The `Int` returned makes a good hash
30+-- | key.
31+foreign import hashUnique :: Unique -> Int
32+
33+uniqSource :: Ref Unique
34+uniqSource = unsafePerformEffect (Ref.new zero)
35+
36+-- | Creates a new object of type `Unique`. The value returned will not compare
37+-- | equal to any other value of type `Unique` returned by previous calls to
38+-- | `newUnique`. There is no limit on the number of times `newUnique` may be
39+-- | called.
40+newUnique :: Effect Unique
41+newUnique = Ref.modify addOne uniqSource