首先,使用Text
or ByteString
代替String
有帮助a lot不改变任何其他东西。
一般来说我不建议创建一个实例Eq
不一致Ord
。图书馆可以理所当然地依赖它,而且你永远不知道它会导致什么样的奇怪问题。 (例如,你是sure that Map
不使用之间的关系Eq
and Ord
?)
如果您不需要Eq
根本没有实例,你可以简单地定义
instance Eq BigThing where
x == y = compare x y == EQ
那么平等就会与比较一致。不要求相等的值必须使所有字段都相等。
如果您需要一个Eq
比较所有字段的实例,那么您可以通过包装来保持一致BigThing
into a newtype
,定义上面的Eq
and Ord
,并在您需要根据以下顺序进行排序时在您的算法中使用它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:既然您说任何排序都是可以接受的,那么您可以使用散列来发挥您的优势。为此,您可以使用hashable包裹。这个想法是,您在数据创建时预先计算哈希值,并在比较值时使用它们。如果两个值不同,几乎可以肯定它们的哈希值会不同,并且您只比较它们的哈希值(两个整数),仅此而已。它可能看起来像这样:
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
请注意,使用此解决方案时,排序看起来是随机的,与字段没有明显的关系。
您还可以将此解决方案与之前的解决方案结合起来。或者,您可以创建一个小模块,用于使用其预先计算的哈希来包装任何类型(包装的值必须具有Eq
与他们一致的实例Hashable
实例)。
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