正如你所指定,在OrdByKey
类只能有一个实例 每个类型,当它听起来像你想能够声明实例 在您的记录类型的每个字段。
要做到这一点,您还必须将字段类型放入类 定义中。这让你做类似如下:
{-# LANGUAGE MultiParamTypeClasses #-}
data Person = Person { name :: String, age :: Int }
class (Ord r) => OrdByKey o r where
orderKey :: o -> r
instance OrdByKey Person Int where
orderKey p = age p
x <=? y = (orderKey x :: Int) <= (orderKey y :: Int)
但是,你只能有每个字段类型一个实例,因此,如果您 Person
类型看起来像
data Person = Person { name :: String, age :: Int, ssn :: String}
,你将不能够有要在name
和 ssn
字段上进行比较的版本。您可以通过将每个字段换成 newtype
来解决此问题,因此每个字段都有唯一的类型。所以,你的Person
类型看起来像
data Person = Person { name :: Name, age :: Age, ssn :: SSN}
这将导致大量的newtypes
左右浮动,但。
真正的缺点是需要指定 orderKey
函数的返回类型。我会建议使用函数从 Data.Function
写出适当的比较函数。我认为像
compareByKey :: (Ord b) => (a -> b) -> a -> a -> Bool
compareByKey = on (<=)
一个 功能概括你的“可以通过一些关键比拟”的想法。在这种情况下,您只需要提供 这个函数来提取该密钥,该密钥恰好就是您的Person
类型的访问器 函数。
我想不出一个实例,其中OrdByKey
类将是有益的,并试图将<=
有多个版本的同一类型的过载好像它会倒在实践中正确 混淆。
如果您的目标仅仅是根据记录中的特定字段进行排序,您总是可以为'Person'定义'Ord'实例来比较该特定字段。 – sabauma 2013-02-08 16:52:58
@sabauma是的,但我正在寻找一种“可以通过一些关键”进行比较的概括。 – 2013-02-08 16:57:54
对于此特定示例,请查看[comparison](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Ord.html#v:comparing)函数:'比较你的年龄我' – 2013-02-09 00:39:45