如何使用构造函数为数据类型正确实现实例 Eq?

How do I correctly implement an instance Eq for a data type with constructors?

我正在为 MyNum 数据类型实现 instance Eq,数据类型为 分数 混合数字 构造函数(每个都有自己的参数)。

我也在使用 helper 函数将 MyNum 转换为 Rational。这应该可以帮助我在 instance Eq.

中进行比较时减少分数

问题是我在创建 instance Eq 时卡住了,我不确定是否还必须为 MyNum 数据类型定义一个新的 class EqEq 的一般目的是在使用辅助方法简化时比较两个分数是否相等。这是我目前所拥有的:

数据类型和构造函数:

data MyNum = Fraction {num :: Integer, denom :: Integer} 
             | Mixed {whole :: Integer, num:: Integer, denom :: Integer}

帮手:

helper :: MyNum -> Rational
helper (Fraction num denom) = (fromIntegral num ) / (fromIntegral denom)

当前 Eq:

instance (Eq n d) => Eq (MyNum n d) where
    Fraction n d == Fraction n d = True
--  Mixed _ _ _ == Mixed _ _ _ = True

上面的 Eq 代码抛出以下错误:

MyNum.hs:29:16: error:
    * Conflicting definitions for `d'
      Bound at: MyNum.hs:29:16
                MyNum.hs:29:32
    * In an equation for `=='
   |
29 |     Fraction n d == Fraction n d = True
   |                ^^^^^^^^^^^^^^^^^

发生这种情况的原因是因为您在 == 方法定义的头部使用了两次 nd,这是不允许的。

Fraction n d == Fraction n d = True中的Fraction n dFraction n d都是模式,并且在左边的多个模式中使用相同的变量= 不允许登录。

您还需要将类型约束写为 (Eq n, Eq d) =>…,而不是 Eq n d,但这里没有区别,因为您不使用 type 参数,所以根本不需要 Eq 约束——你的 MyNum 类型使用的值的类型,它们都是 Integers,已经是 [= 的一个实例19=]:

instance Eq MyNum where
    Fraction <b>n1</b> <b>d1</b> == Fraction <b>n2</b> <b>d2</b> | <b>n1 == n2 && d1 == d2</b>  =  True
    -- …

Prolog,与unification一起工作,确实允许我们在头部多次使用同一个变量,以表示相等。

但是 Haskell 与 模式匹配 一起工作,因此不完全清楚重用同一个变量意味着什么,特别是因为不是每个类型都是Eq.

您可能想利用您的 helper 函数将两个 MyNum 转换为 Rational,以便您可以比较它们:

instance Eq MyNum where
   x == y  =  helper x == helper y

你的typeMyNum不带任何参数,所以你不能写Eq (MyNum n d)ndFraction 数据构造函数的参数,而不是类型。由于这些值由助手处理,我们也不需要在实例定义中关心它们。

请注意,要使上述实例正常工作,helper 必须处理两种形式的数字,FractionMixed

helper:: MyNum -> Rational
helper (Fraction num denom)    = fromIntegral num / fromIntegral denom
helper (Mixed whole num denom) = ...