2013-02-08 43 views
3

是否有可能有一个类型类型暗示Haskell中的另一个类型类型?例如,让我们说有一堆“东西”,可以通过“属性”进行排序:Haskell:Typeclass意味着其他类型类型

data Person = Person { name :: String, age :: Int } 

Person p1 <= Person p1 = (age p1) <= (age p2) 

为了避免重复一个可以定义一个“订购的钥匙”类型的类

class OrdByKey o where 
    orderKey :: (Ord r) => o -> r 
    x <= y = (orderKey x) <= (orderKey y) 

那么对于Person的实例声明看起来是这样的

instance OrdByKey Person where 
    orderKey Person p = age p 

现在这样做显然不是出于多种原因的工作。我想知道这是否可能?

+2

如果您的目标仅仅是根据记录中的特定字段进行排序,您总是可以为'Person'定义'Ord'实例来比较该特定字段。 – sabauma 2013-02-08 16:52:58

+0

@sabauma是的,但我正在寻找一种“可以通过一些关键”进行比较的概括。 – 2013-02-08 16:57:54

+0

对于此特定示例,请查看[comparison](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Ord.html#v:comparing)函数:'比较你的年龄我' – 2013-02-09 00:39:45

回答

2

正如你所指定,在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} 

,你将不能够有要在namessn字段上进行比较的版本。您可以通过将每个字段换成 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类将是有益的,并试图将<=有多个版本的同一类型的过载好像它会倒在实践中正确 混淆。

+0

看起来像使用多参数类型的类是干净的方式来做到这一点。谢谢! – 2013-02-09 10:52:14

0

你可以这样做:

instance Ord Person where 
    compare p1 p2 = compare (age p1) (age p2) 

现在的标准<=操作符的作用Person S和比较他们的年龄。

相关问题