Haskell:Typeclass暗示其他类型

是否有可能有一个类型类型暗示Haskell中的另一个类型类? 例如,让我们说有一堆“事物”可以通过“属性”进行排序:

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

由于多种原因,现在这显然不起作用。 我想知道这是否可能?


正如你指定的那样, 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.Functionon函数来编写适当的比较函数。 我觉得像一个功能

compareByKey :: (Ord b) => (a -> b) -> a -> a -> Bool
compareByKey = on (<=)

推广你的“可以通过一些关键比较”的想法。 在这种情况下,您只需提供一个提取该键的函数,该函数就是Person类型的访问函数。

我想不出一个OrdByKey类会很有用的实例,并且试图用同一类型的多个版本来重载<=好像它在实践中会混淆一样。


你可以这样做:

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

现在标准的<=运算符将在Person工作并比较他们的年龄。

链接地址: http://www.djcxy.com/p/43469.html

上一篇: Haskell: Typeclass implies other typeclass

下一篇: What is the Comonad typeclass in Haskell?