Zuerst mit Text
oder ByteString
statt String
viel ohne etwas anderes ändern helfen könnte.
Im Allgemeinen würde ich nicht empfehlen, eine Instanz von Eq
zu erstellen, die mit Ord
inkonsistent ist. Bibliotheken können sich zu Recht darauf verlassen, und Sie wissen nie, welche Art von seltsamen Problemen es verursachen kann. (Zum Beispiel sind Sie sicher dass Map
nicht die Beziehung nicht verwendet zwischen Eq
und Ord
?)
Wenn Sie die Eq
Instanz nicht brauchen überhaupt, können Sie einfach definieren
instance Eq BigThing where
x == y = compare x y == EQ
Dann wird die Gleichheit mit dem Vergleich übereinstimmen. Es ist nicht erforderlich, dass bei gleichen Werten alle Felder gleich sind.
Wenn Sie eine Eq
Instanz benötigen, der alle Felder vergleicht, dann können Sie konsistent bleiben, indem sie BigThing
in eine newtype
, definieren die oben Eq
und Ord
dafür Einwickeln und es in Ihrem Algorithmus verwenden, wann immer Sie benötigen Bestellung nach zu name
:
newtype BigThing' a b c = BigThing' (BigThing a b c)
instance Eq BigThing' where
x == y = compare x y == EQ
instance Ord BigThing' where
compare (BigThing b) (BigThing b') = compare (name b) (name b')
Update: Da sagen Sie jede Bestellung akzeptabel ist, ca Sie Nutzen Sie Hashing zu Ihrem Vorteil. Dazu können Sie das Paket hashable verwenden. Die Idee ist, dass Sie Hashwerte bei der Datenerstellung vorberechnen und beim Vergleichen von Werten verwenden. Wenn zwei Werte unterschiedlich sind, ist es fast sicher, dass ihre Hashes sich unterscheiden und Sie nur ihre Hashes (zwei ganze Zahlen) vergleichen, nichts mehr. Es könnte wie folgt aussehen:
module BigThing
(BigThing()
, bigThing
, btHash, btName, btSurname
)
where
import Data.Hashable
data BigThing = BigThing { btHash :: Int,
btName :: String,
btSurname :: String } -- etc
deriving (Eq, Ord)
-- Since the derived Eq/Ord instances compare fields lexicographically and
-- btHash is the first, they'll compare the hash first and continue with the
-- other fields only if the hashes are equal.
-- See http://www.haskell.org/onlinereport/derived.html#sect10.1
--
-- Alternativelly, you can create similar Eq/Ord instances yourself, if for any
-- reason you don't want the hash to be the first field.
-- A smart constructor for creating instances. Your module will not export the
-- BigThing constructor, it will export this function instead:
bigThing :: String -> String -> BigThing
bigThing nm snm = BigThing (hash (nm, snm)) nm snm
Beachten Sie, dass mit dieser Lösung wird die Bestellung auf die Felder ohne erkennbare Beziehung scheinbar zufällig sein.
Sie können diese Lösung auch mit den vorherigen kombinieren. Oder Sie können ein kleines Modul zum Umbrechen eines beliebigen Typs mit seinem vorberechneten Hash erstellen (umbrochene Werte müssen Eq
Instanzen haben, die mit ihren Hashable
Instanzen konsistent sind).
module HashOrd
(Hashed()
, getHashed
, hashedHash
)
where
import Data.Hashable
data Hashed a = Hashed { hashedHash :: Int, getHashed :: a }
deriving (Ord, Eq, Show, Read, Bounded)
hashed :: (Hashable a) => a -> Hashed a
hashed x = Hashed (hash x) x
instance Hashable a => Hashable (Hashed a) where
hashWithSalt salt (Hashed _ x) = hashWithSalt salt x
Ich habe es getan, aber müssen Sie vorsichtig sein, welche Bibliotheken Sie verwenden. – augustss
Sie müssen nach 'name' bestellen, oder ist irgendeine Art von beständiger Bestellung akzeptabel, nur so dass Sie' Map's verwenden können und es schnell geht? –
Jede Bestellung ist akzeptabel. – Maxander