From 3d52f992cca35d5169f9e10a9c89ce1b0daecd35 Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Thu, 11 Oct 2018 20:21:17 +0200 Subject: [PATCH 1/8] Add Hashable class --- src/Data/Hashable.js | 38 +++++++++++++++++ src/Data/Hashable.purs | 93 ++++++++++++++++++++++++++++++++++++++++++ test/Test/Main.purs | 2 + 3 files changed, 133 insertions(+) create mode 100644 src/Data/Hashable.js create mode 100644 src/Data/Hashable.purs diff --git a/src/Data/Hashable.js b/src/Data/Hashable.js new file mode 100644 index 00000000..311e5a7a --- /dev/null +++ b/src/Data/Hashable.js @@ -0,0 +1,38 @@ +"use strict"; + +exports.hashNumber = function (o) { + if (o !== o || o === Infinity) { + return 0; + } + var h = o | 0; + if (h !== o) { + h ^= o * 0xffffffff; + } + while (o > 0xffffffff) { + o /= 0xffffffff; + h ^= o; + } + return h; +}; + +exports.hashString = function (s) { + var h = 0; + for (var i = 0; i < s.length; i++) { + h = (31 * h + s.charCodeAt(i)) | 0; + } + return h; +}; + +exports.hashArray = function (hash) { + return function (as) { + var h = 0; + for (var i = 0; i < as.length; i++) { + h = (31 * h + hash(as[i])) | 0; + } + return h; + }; +}; + +exports.hashChar = function (c) { + return c.charCodeAt(0); +}; diff --git a/src/Data/Hashable.purs b/src/Data/Hashable.purs new file mode 100644 index 00000000..d59149fa --- /dev/null +++ b/src/Data/Hashable.purs @@ -0,0 +1,93 @@ +module Data.Hashable ( + class Hashable, + hash, + + class HashableRecord, + hashRecord +) where + +import Data.Eq (class Eq, class EqRecord) +import Data.Semiring ((*), (+)) +import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) +import Data.Unit (Unit) +import Data.Void (Void) +import Prim.Row as Row +import Prim.RowList (class RowToList, Cons, Nil, kind RowList) +import Record.Unsafe (unsafeGet) +import Type.Data.RowList (RLProxy(..)) + +-- | The `Hashable` type class represents types with decidable +-- | equality and a hash function whose result can approximate +-- | equality for use in hash-based algorithms and data structures. +-- | +-- | Instances of `Hashable` must satisfy the following law: +-- | +-- | ```PureScript +-- | (a == b) `implies` (hash a == hash b) +-- | ``` +-- | +-- | That is, unequal hash values are a safe approximation of +-- | inequality. In other words, two objects whose hash values differ, +-- | are never equal. The reverse is not necessarily true. +-- | +-- | Hash values produced by `hash` should not be relied upon to be +-- | stable accross multiple executions of a program and should not be +-- | stored externally. +class Eq a <= Hashable a where + hash :: a -> Int + +instance hashableBoolean :: Hashable Boolean where + hash false = 0 + hash true = 1 + +instance hashableInt :: Hashable Int where + hash n = n + +foreign import hashNumber :: Number -> Int + +instance hashableNumber :: Hashable Number where + hash = hashNumber + +foreign import hashChar :: Char -> Int + +instance hashableChar :: Hashable Char where + hash = hashChar + +foreign import hashString :: String -> Int + +instance hashableString :: Hashable String where + hash = hashString + +foreign import hashArray :: forall a. (a -> Int) -> Array a -> Int + +instance hashableArray :: Hashable a => Hashable (Array a) where + hash = hashArray hash + +instance hashableUnit :: Hashable Unit where + hash _ = 1 + +instance hashableVoid :: Hashable Void where + hash _ = 0 + +class EqRecord l r <= HashableRecord l r | l -> r where + hashRecord :: RLProxy l -> Record r -> Int + +instance hashableRecordNil :: HashableRecord Nil r where + hashRecord _ _ = 0 + +instance hashableRecordCons :: + ( Hashable vt + , HashableRecord tl r + , IsSymbol l + , Row.Cons l vt whatev r + ) => HashableRecord (Cons l vt tl) r where + hashRecord rlp record = + hash field * 31 + hashRecord (RLProxy :: RLProxy tl) record + where + field :: vt + field = unsafeGet (reflectSymbol (SProxy :: SProxy l)) record + +instance hashableRecord :: + (RowToList r l, HashableRecord l r, EqRecord l r) + => Hashable (Record r) where + hash = hashRecord (RLProxy :: RLProxy l) diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 2a7a896b..aab1e76f 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -3,6 +3,7 @@ module Test.Main where import Prelude import Data.HeytingAlgebra (ff, tt, implies) import Data.Ord (abs) +import Data.Hashable (hash) type AlmostEff = Unit -> Unit @@ -120,6 +121,7 @@ testIntDegree = do testRecordInstances :: AlmostEff testRecordInstances = do assert "Record equality" $ { a: 1 } == { a: 1 } + assert "Record hash" $ hash { a: 1 } == hash { a: 1 } assert "Record inequality" $ { a: 2 } /= { a: 1 } assert "Record show" $ show { a: 1 } == "{ a: 1 }" assert "Record +" $ ({ a: 1, b: 2.0 } + { a: 0, b: (-2.0) }) == { a: 1, b: 0.0 } From 7a3ab4a76b88280186cd52960560a35c28e14cdb Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Thu, 11 Oct 2018 20:29:48 +0200 Subject: [PATCH 2/8] Improve Hashable Boolean --- src/Data/Hashable.purs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Data/Hashable.purs b/src/Data/Hashable.purs index d59149fa..2ff9405b 100644 --- a/src/Data/Hashable.purs +++ b/src/Data/Hashable.purs @@ -37,8 +37,7 @@ class Eq a <= Hashable a where hash :: a -> Int instance hashableBoolean :: Hashable Boolean where - hash false = 0 - hash true = 1 + hash b = if b then 1 else 0 instance hashableInt :: Hashable Int where hash n = n From 73ba14c80b7bd957250a510bdf464594cc781ce2 Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Thu, 11 Oct 2018 20:44:18 +0200 Subject: [PATCH 3/8] Spaces and whatnot --- src/Data/Hashable.js | 53 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/Data/Hashable.js b/src/Data/Hashable.js index 311e5a7a..6fb5ac90 100644 --- a/src/Data/Hashable.js +++ b/src/Data/Hashable.js @@ -1,38 +1,39 @@ "use strict"; -exports.hashNumber = function (o) { - if (o !== o || o === Infinity) { - return 0; - } - var h = o | 0; - if (h !== o) { - h ^= o * 0xffffffff; - } - while (o > 0xffffffff) { - o /= 0xffffffff; - h ^= o; - } - return h; +exports.hashNumber = function (f) { + var o = f; + if (o !== o || o === Infinity) { + return 0; + } + var h = o | 0; + if (h !== o) { + h ^= o * 0xffffffff; + } + while (o > 0xffffffff) { + o /= 0xffffffff; + h ^= o; + } + return h; }; exports.hashString = function (s) { - var h = 0; - for (var i = 0; i < s.length; i++) { - h = (31 * h + s.charCodeAt(i)) | 0; - } - return h; + var h = 0; + for (var i = 0; i < s.length; i++) { + h = (31 * h + s.charCodeAt(i)) | 0; + } + return h; }; exports.hashArray = function (hash) { - return function (as) { - var h = 0; - for (var i = 0; i < as.length; i++) { - h = (31 * h + hash(as[i])) | 0; - } - return h; - }; + return function (as) { + var h = 0; + for (var i = 0; i < as.length; i++) { + h = (31 * h + hash(as[i])) | 0; + } + return h; + }; }; exports.hashChar = function (c) { - return c.charCodeAt(0); + return c.charCodeAt(0); }; From 7ee0dab0c4cad300afdf6e731090b0fdae2b0193 Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Sat, 20 Oct 2018 11:24:45 +0200 Subject: [PATCH 4/8] Add comments about hash functions and fix the record hash function in the process --- src/Data/Hashable.js | 3 +++ src/Data/Hashable.purs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Data/Hashable.js b/src/Data/Hashable.js index 6fb5ac90..c549aad9 100644 --- a/src/Data/Hashable.js +++ b/src/Data/Hashable.js @@ -1,5 +1,6 @@ "use strict"; +// Same as immutable.js, except for not dropping the highest bit. exports.hashNumber = function (f) { var o = f; if (o !== o || o === Infinity) { @@ -16,6 +17,7 @@ exports.hashNumber = function (f) { return h; }; +// Same as Java. Improvements welcome. exports.hashString = function (s) { var h = 0; for (var i = 0; i < s.length; i++) { @@ -24,6 +26,7 @@ exports.hashString = function (s) { return h; }; +// Almost the same as Java. Improvements welcome. exports.hashArray = function (hash) { return function (as) { var h = 0; diff --git a/src/Data/Hashable.purs b/src/Data/Hashable.purs index 2ff9405b..5985c670 100644 --- a/src/Data/Hashable.purs +++ b/src/Data/Hashable.purs @@ -81,7 +81,8 @@ instance hashableRecordCons :: , Row.Cons l vt whatev r ) => HashableRecord (Cons l vt tl) r where hashRecord rlp record = - hash field * 31 + hashRecord (RLProxy :: RLProxy tl) record + -- this mimicks Java's hash function for arrays + hashRecord (RLProxy :: RLProxy tl) record * 31 + hash field where field :: vt field = unsafeGet (reflectSymbol (SProxy :: SProxy l)) record From bc4c9c1588d797a3377bfa49940aeaa01a1da60a Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Tue, 23 Oct 2018 20:45:52 +0200 Subject: [PATCH 5/8] Hash code is an indexed newtype --- src/Data/Hashable.purs | 61 +++++++++++++++++++++++++++++------------- src/Prelude.purs | 2 ++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/Data/Hashable.purs b/src/Data/Hashable.purs index 5985c670..ca70e419 100644 --- a/src/Data/Hashable.purs +++ b/src/Data/Hashable.purs @@ -3,11 +3,18 @@ module Data.Hashable ( hash, class HashableRecord, - hashRecord + hashRecord, + + Hash(Hash) ) where import Data.Eq (class Eq, class EqRecord) +import Data.Ord (class Ord) +import Data.Ordering (Ordering(..)) +import Data.Ring (negate) +import Data.Semigroup ((<>)) import Data.Semiring ((*), (+)) +import Data.Show (class Show, show) import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) import Data.Unit (Unit) import Data.Void (Void) @@ -25,54 +32,71 @@ import Type.Data.RowList (RLProxy(..)) -- | ```PureScript -- | (a == b) `implies` (hash a == hash b) -- | ``` --- | +-- | -- | That is, unequal hash values are a safe approximation of -- | inequality. In other words, two objects whose hash values differ, -- | are never equal. The reverse is not necessarily true. -- | --- | Hash values produced by `hash` should not be relied upon to be +-- | Hash values produced by `hash` must not be relied upon to be -- | stable accross multiple executions of a program and should not be -- | stored externally. class Eq a <= Hashable a where - hash :: a -> Int + hash :: a -> Hash a + +-- | The `Hash a` newtype wraps the hash code of a value of type `a`. +-- | +-- | Hash values should not be stored externally, as they must not be +-- | relied upon to be stable accross multiple executions of a +-- | program. +newtype Hash a = Hash Int + +instance showHash :: Show (Hash a) where + show (Hash n) = "(Hash " <> show n <> ")" +derive newtype instance eqHash :: Eq (Hash a) +derive newtype instance ordHash :: Ord (Hash a) instance hashableBoolean :: Hashable Boolean where - hash b = if b then 1 else 0 + hash b = if b then Hash 1 else Hash 0 instance hashableInt :: Hashable Int where - hash n = n + hash n = Hash n -foreign import hashNumber :: Number -> Int +foreign import hashNumber :: Number -> Hash Number instance hashableNumber :: Hashable Number where hash = hashNumber -foreign import hashChar :: Char -> Int +foreign import hashChar :: Char -> Hash Char instance hashableChar :: Hashable Char where hash = hashChar -foreign import hashString :: String -> Int +foreign import hashString :: String -> Hash String instance hashableString :: Hashable String where hash = hashString -foreign import hashArray :: forall a. (a -> Int) -> Array a -> Int +foreign import hashArray :: forall a. (a -> Hash a) -> Array a -> Hash (Array a) instance hashableArray :: Hashable a => Hashable (Array a) where hash = hashArray hash instance hashableUnit :: Hashable Unit where - hash _ = 1 + hash _ = Hash 1 instance hashableVoid :: Hashable Void where - hash _ = 0 + hash _ = Hash 0 + +instance hashableOrdering :: Hashable Ordering where + hash LT = Hash (-1) + hash GT = Hash 1 + hash EQ = Hash 0 class EqRecord l r <= HashableRecord l r | l -> r where - hashRecord :: RLProxy l -> Record r -> Int + hashRecord :: RLProxy l -> Record r -> Hash (Record r) instance hashableRecordNil :: HashableRecord Nil r where - hashRecord _ _ = 0 + hashRecord _ _ = Hash 0 instance hashableRecordCons :: ( Hashable vt @@ -81,11 +105,12 @@ instance hashableRecordCons :: , Row.Cons l vt whatev r ) => HashableRecord (Cons l vt tl) r where hashRecord rlp record = + let (Hash rHash) = hashRecord (RLProxy :: RLProxy tl) record + field :: vt + field = unsafeGet (reflectSymbol (SProxy :: SProxy l)) record + (Hash fHash) = hash field -- this mimicks Java's hash function for arrays - hashRecord (RLProxy :: RLProxy tl) record * 31 + hash field - where - field :: vt - field = unsafeGet (reflectSymbol (SProxy :: SProxy l)) record + in Hash (rHash * 31 + fHash) instance hashableRecord :: (RowToList r l, HashableRecord l r, EqRecord l r) diff --git a/src/Prelude.purs b/src/Prelude.purs index 3a1cd439..01eda529 100644 --- a/src/Prelude.purs +++ b/src/Prelude.purs @@ -15,6 +15,7 @@ module Prelude , module Data.Field , module Data.Function , module Data.Functor + , module Data.Hashable , module Data.HeytingAlgebra , module Data.Monoid , module Data.NaturalTransformation @@ -45,6 +46,7 @@ import Data.EuclideanRing (class EuclideanRing, degree, div, mod, (/), gcd, lcm) import Data.Field (class Field) import Data.Function (const, flip, ($), (#)) import Data.Functor (class Functor, flap, map, void, ($>), (<#>), (<$), (<$>), (<@>)) +import Data.Hashable (class Hashable, Hash(..), hash) import Data.HeytingAlgebra (class HeytingAlgebra, conj, disj, not, (&&), (||)) import Data.Monoid (class Monoid, mempty) import Data.NaturalTransformation (type (~>)) From 1c3d4f73a6041cf6cc60f567b4e97152a34cd8cd Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Fri, 26 Oct 2018 14:41:26 +0200 Subject: [PATCH 6/8] Fix spelling --- src/Data/Hashable.purs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Hashable.purs b/src/Data/Hashable.purs index ca70e419..b47d01b8 100644 --- a/src/Data/Hashable.purs +++ b/src/Data/Hashable.purs @@ -38,7 +38,7 @@ import Type.Data.RowList (RLProxy(..)) -- | are never equal. The reverse is not necessarily true. -- | -- | Hash values produced by `hash` must not be relied upon to be --- | stable accross multiple executions of a program and should not be +-- | stable across multiple executions of a program and should not be -- | stored externally. class Eq a <= Hashable a where hash :: a -> Hash a @@ -46,7 +46,7 @@ class Eq a <= Hashable a where -- | The `Hash a` newtype wraps the hash code of a value of type `a`. -- | -- | Hash values should not be stored externally, as they must not be --- | relied upon to be stable accross multiple executions of a +-- | relied upon to be stable across multiple executions of a -- | program. newtype Hash a = Hash Int @@ -109,7 +109,7 @@ instance hashableRecordCons :: field :: vt field = unsafeGet (reflectSymbol (SProxy :: SProxy l)) record (Hash fHash) = hash field - -- this mimicks Java's hash function for arrays + -- this mimics Java's hash function for arrays in Hash (rHash * 31 + fHash) instance hashableRecord :: From eb3ffa11a7b87776dc97929c812bb2fabb3b11bc Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Fri, 8 Mar 2019 15:19:13 +0000 Subject: [PATCH 7/8] hashWithSalt --- src/Data/Hashable.js | 69 +++++++++++++++++++++++------------------- src/Data/Hashable.purs | 67 +++++++++++++++++++++------------------- src/Prelude.purs | 2 +- 3 files changed, 75 insertions(+), 63 deletions(-) diff --git a/src/Data/Hashable.js b/src/Data/Hashable.js index c549aad9..dfa83a84 100644 --- a/src/Data/Hashable.js +++ b/src/Data/Hashable.js @@ -1,42 +1,49 @@ "use strict"; -// Same as immutable.js, except for not dropping the highest bit. -exports.hashNumber = function (f) { - var o = f; - if (o !== o || o === Infinity) { - return 0; - } - var h = o | 0; - if (h !== o) { - h ^= o * 0xffffffff; - } - while (o > 0xffffffff) { - o /= 0xffffffff; - h ^= o; - } - return h; +// Inspired by immutable.js, except for not dropping the highest bit +// and taking a seed. +exports.hashNumber = function (s) { + return function (f) { + var o = f; + if (o !== o || o === Infinity) { + return s; + } + var h = o | 0; + if (h !== o) { + h ^= o * 0xffffffff; + } + while (o > 0xffffffff) { + o /= 0xffffffff; + h ^= o; + } + return (s+h)|0; + }; }; -// Same as Java. Improvements welcome. -exports.hashString = function (s) { - var h = 0; - for (var i = 0; i < s.length; i++) { - h = (31 * h + s.charCodeAt(i)) | 0; - } - return h; +exports.hashString = function (seed) { + return function (s) { + var h = s; + for (var i = 0; i < s.length; i++) { + h = (31 * h + s.charCodeAt(i)) | 0; + } + return h; + }; }; -// Almost the same as Java. Improvements welcome. exports.hashArray = function (hash) { - return function (as) { - var h = 0; - for (var i = 0; i < as.length; i++) { - h = (31 * h + hash(as[i])) | 0; - } - return h; + return function (s) { + return function (as) { + var h = s; + for (var i = 0; i < as.length; i++) { + h = (31 * h + hash(as[i])) | 0; + } + return h; + }; }; }; -exports.hashChar = function (c) { - return c.charCodeAt(0); +exports.hashChar = function (s) { + return function (c) { + return (s+c.charCodeAt(0))|0; + }; }; diff --git a/src/Data/Hashable.purs b/src/Data/Hashable.purs index b47d01b8..b2fb82ea 100644 --- a/src/Data/Hashable.purs +++ b/src/Data/Hashable.purs @@ -1,5 +1,6 @@ module Data.Hashable ( class Hashable, + hashWithSalt, hash, class HashableRecord, @@ -11,7 +12,7 @@ module Data.Hashable ( import Data.Eq (class Eq, class EqRecord) import Data.Ord (class Ord) import Data.Ordering (Ordering(..)) -import Data.Ring (negate) +import Data.Ring ((-)) import Data.Semigroup ((<>)) import Data.Semiring ((*), (+)) import Data.Show (class Show, show) @@ -24,79 +25,84 @@ import Record.Unsafe (unsafeGet) import Type.Data.RowList (RLProxy(..)) -- | The `Hashable` type class represents types with decidable --- | equality and a hash function whose result can approximate +-- | equality and a seeded hash function whose result can approximate -- | equality for use in hash-based algorithms and data structures. -- | -- | Instances of `Hashable` must satisfy the following law: -- | -- | ```PureScript --- | (a == b) `implies` (hash a == hash b) +-- | (a == b) `implies` (hashWithSalt s a == hashWithSalt s b) -- | ``` -- | -- | That is, unequal hash values are a safe approximation of -- | inequality. In other words, two objects whose hash values differ, -- | are never equal. The reverse is not necessarily true. -- | --- | Hash values produced by `hash` must not be relied upon to be --- | stable across multiple executions of a program and should not be --- | stored externally. +-- | Hash values produced by `hashWithSalt` are not cryptographically +-- | secure, must not be relied upon to be stable across multiple +-- | executions of a program, and should not be stored externally. class Eq a <= Hashable a where - hash :: a -> Hash a + hashWithSalt :: Int -> a -> Hash a -- | The `Hash a` newtype wraps the hash code of a value of type `a`. -- | -- | Hash values should not be stored externally, as they must not be --- | relied upon to be stable across multiple executions of a --- | program. +-- | relied upon to be stable across multiple executions of a program. newtype Hash a = Hash Int +-- | A convenience function that calls `hashWithSalt` on its argument +-- | with some seed. This seed is fixed for the runtime of a program, +-- | but may change between runs. Do not store hashes externally. +hash :: forall a. Hashable a => a -> Hash a +hash = hashWithSalt 42 + instance showHash :: Show (Hash a) where show (Hash n) = "(Hash " <> show n <> ")" derive newtype instance eqHash :: Eq (Hash a) derive newtype instance ordHash :: Ord (Hash a) instance hashableBoolean :: Hashable Boolean where - hash b = if b then Hash 1 else Hash 0 + hashWithSalt s b = Hash (s + if b then 1 else 0) instance hashableInt :: Hashable Int where - hash n = Hash n + hashWithSalt s n = Hash (s + n) -foreign import hashNumber :: Number -> Hash Number +foreign import hashNumber :: Int -> Number -> Hash Number instance hashableNumber :: Hashable Number where - hash = hashNumber + hashWithSalt = hashNumber -foreign import hashChar :: Char -> Hash Char +foreign import hashChar :: Int -> Char -> Hash Char instance hashableChar :: Hashable Char where - hash = hashChar + hashWithSalt = hashChar -foreign import hashString :: String -> Hash String +foreign import hashString :: Int -> String -> Hash String instance hashableString :: Hashable String where - hash = hashString + hashWithSalt = hashString -foreign import hashArray :: forall a. (a -> Hash a) -> Array a -> Hash (Array a) +foreign import hashArray :: forall a. (a -> Hash a) -> Int -> Array a -> Hash (Array a) instance hashableArray :: Hashable a => Hashable (Array a) where - hash = hashArray hash + hashWithSalt = hashArray hash instance hashableUnit :: Hashable Unit where - hash _ = Hash 1 + hashWithSalt s _ = Hash (s + 1) instance hashableVoid :: Hashable Void where - hash _ = Hash 0 + hashWithSalt s _ = Hash s instance hashableOrdering :: Hashable Ordering where - hash LT = Hash (-1) - hash GT = Hash 1 - hash EQ = Hash 0 + hashWithSalt s LT = Hash (s - 1) + hashWithSalt s GT = Hash (s + 1) + hashWithSalt s EQ = Hash (s + 0) class EqRecord l r <= HashableRecord l r | l -> r where - hashRecord :: RLProxy l -> Record r -> Hash (Record r) + hashRecord :: Int -> RLProxy l -> Record r -> Hash (Record r) instance hashableRecordNil :: HashableRecord Nil r where - hashRecord _ _ = Hash 0 + hashRecord s _ _ = Hash s instance hashableRecordCons :: ( Hashable vt @@ -104,15 +110,14 @@ instance hashableRecordCons :: , IsSymbol l , Row.Cons l vt whatev r ) => HashableRecord (Cons l vt tl) r where - hashRecord rlp record = - let (Hash rHash) = hashRecord (RLProxy :: RLProxy tl) record + hashRecord s rlp record = + let (Hash rHash) = hashRecord s (RLProxy :: RLProxy tl) record field :: vt field = unsafeGet (reflectSymbol (SProxy :: SProxy l)) record - (Hash fHash) = hash field - -- this mimics Java's hash function for arrays + (Hash fHash) = hashWithSalt s field in Hash (rHash * 31 + fHash) instance hashableRecord :: (RowToList r l, HashableRecord l r, EqRecord l r) => Hashable (Record r) where - hash = hashRecord (RLProxy :: RLProxy l) + hashWithSalt s = hashRecord s (RLProxy :: RLProxy l) diff --git a/src/Prelude.purs b/src/Prelude.purs index 01eda529..f1744b06 100644 --- a/src/Prelude.purs +++ b/src/Prelude.purs @@ -46,7 +46,7 @@ import Data.EuclideanRing (class EuclideanRing, degree, div, mod, (/), gcd, lcm) import Data.Field (class Field) import Data.Function (const, flip, ($), (#)) import Data.Functor (class Functor, flap, map, void, ($>), (<#>), (<$), (<$>), (<@>)) -import Data.Hashable (class Hashable, Hash(..), hash) +import Data.Hashable (class Hashable, Hash(..), hash, hashWithSalt) import Data.HeytingAlgebra (class HeytingAlgebra, conj, disj, not, (&&), (||)) import Data.Monoid (class Monoid, mempty) import Data.NaturalTransformation (type (~>)) From 08dd4b26125b964fde629d55f7fd361f365f46c6 Mon Sep 17 00:00:00 2001 From: Stefan Fehrenbach Date: Fri, 8 Mar 2019 18:00:29 +0000 Subject: [PATCH 8/8] Remove redundant import --- test/Test/Main.purs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Test/Main.purs b/test/Test/Main.purs index aab1e76f..95627438 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -3,7 +3,6 @@ module Test.Main where import Prelude import Data.HeytingAlgebra (ff, tt, implies) import Data.Ord (abs) -import Data.Hashable (hash) type AlmostEff = Unit -> Unit