简体   繁体   English

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

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

I am implementing an instance Eq for MyNum data type that has Fractions and Mixed Numbers as data constructors (each one with its own arguments).我正在为MyNum数据类型实现一个instance Eq ,它具有分数混合数作为数据构造函数(每个都有自己的参数)。

I am also using a helper function to convert from MyNum to Rational .我还使用helper function 从MyNum转换为Rational This should help me reduce fractions when doing comparisons in the instance Eq .这应该有助于我在instance Eq中进行比较时减少分数。

The problem is I am getting stuck when creating the instance Eq and I am not sure whether I also have to define a new class Eq for the MyNum data type.问题是我在创建instance Eq时卡住了,我不确定是否还必须为MyNum数据类型定义一个新的class Eq The general purpose of the Eq is to compare whether two fractions are equal when simplified with the helper method. Eq的一般目的是在使用辅助方法简化时比较两个分数是否相等。 Here is what I have so far:这是我到目前为止所拥有的:

Data Type and Constructors:数据类型和构造函数:

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

Helper:帮手:

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

Current Eq :电流Eq

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

The above Eq code throws the following error:上面的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 nd == Fraction nd = True | ^^^^^^^^^^^^^^^^^

The reason this happens is because you use n and d twice in the head of your == method definition, which is not allowed.发生这种情况的原因是因为您在==方法定义的头部使用了两次nd ,这是不允许的。

Both Fraction nd and Fraction nd in Fraction nd == Fraction nd = True are patterns , and using the same variable in more than one pattern on the left of the = sign in not allowed. Fraction nd == Fraction nd = True中的Fraction ndFraction nd都是模式,并且不允许在=符号左侧的多个模式中使用相同的变量。

You would also need to write the type constraints as (Eq n, Eq d) =>… , and not Eq nd , but here it makes no difference since you do not use type parameters anyway, so no Eq constraint is needed at all -- the type of the values used by your MyNum type, which are all Integer s, already is an instance of Eq :您还需要将类型约束写为(Eq n, Eq d) =>… ,而不是Eq nd ,但在这里它没有区别,因为您不使用类型参数,所以根本不需要Eq约束 - - 您的MyNum类型使用的值的类型,它们都是Integer s,已经是Eq的一个实例:

instance Eq MyNum where
    Fraction n1 d1 == Fraction n2 d2 | n1 == n2 && d1 == d2  =  True
    -- …

Prolog, which works with unification indeed allows us to use the same variable multiple times in the head, to indicate equality. Prolog 与统一一起工作确实允许我们在头部多次使用相同的变量,以表示相等。

But Haskell works with pattern matching , and it is therefore not entirely clear what reusing the same variable would mean, especially since not every type is an instance of Eq .但是 Haskell 与模式匹配一起工作,因此不完全清楚重用相同变量的含义,特别是因为并非每种类型都是Eq的实例。

You might want to exploit your helper function to convert both MyNum s into Rational s so that you can compare them:您可能想利用您的helper function 将两个MyNum转换为Rational以便您可以比较它们:

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

Your type MyNum does not take any parameters, so you can't write Eq (MyNum nd) .您的MyNum类型不带任何参数,因此您不能编写Eq (MyNum nd) The n and d are values , arguments for the Fraction data constructor, not the type. nd,arguments 用于Fraction数据构造函数,而不是类型。 Since these values are handled by the helper, we don't need to care about them in the instance definition either.由于这些值由助手处理,我们也不需要在实例定义中关心它们。

Note that, for the above instance to work, helper must deal with both forms of number, Fraction and Mixed .请注意,要使上述实例起作用, helper必须同时处理数字、 FractionMixed的 forms 。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM