【问题标题】:Haskell: Typeclass implies other typeclassHaskell:类型类暗示其他类型类
【发布时间】:2013-02-08 16:47:22
【问题描述】:

是否有可能在 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

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

【问题讨论】:

  • 如果您的目标只是根据记录中的特定字段进行排序,您始终可以为Person 定义Ord 的实例来比较该特定字段。
  • @sabauma 是的,但我正在寻找“可以通过一些关键比较”的东西的概括。
  • 对于这个特定的例子,看看comparing函数:comparing age you me
  • 对于更通用的运算符然后comparing,您可以查看on。它的类型为 (b -&gt; b -&gt; c) -&gt; (a -&gt; b) -&gt; a -&gt; a -&gt; c,所以是 comparing age = on compare age,但您也可以在应用 f 后使用 on (==) f 来测试两件事是否相等。

标签: haskell


【解决方案1】:

正如你所指定的,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 函数。我建议使用on 函数 Data.Function 编写相应的比较函数。我认为一个 功能类似

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

概括了您“可以通过某些键进行比较”的想法。你只需要付出 它是提取该密钥的函数,这正是访问器 Person 类型的函数,在这种情况下。

我想不出OrdByKey 类会有用的实例,并且尝试用同一类型的多个版本重载&lt;= 似乎是正确的 在实践中令人困惑。

【讨论】:

  • 看起来使用多参数类型类是一种干净的方法。谢谢!
【解决方案2】:

你可以这样做:

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

现在标准的&lt;= 运算符将在Persons 上工作并比较他们的年龄。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多