【问题标题】:How do I correctly implement an instance Eq for a data type with constructors?如何使用构造函数正确实现数据类型的实例 Eq?
【发布时间】:2021-03-06 09:16:43
【问题描述】:

我正在为 MyNum 数据类型实现一个 instance Eq,它具有 Fractions 和 Mixed Numbers 作为数据构造函数(每个都有自己的参数)。

我还使用helper 函数将MyNum 转换为Rational。这应该有助于我在instance Eq 中进行比较时减少分数。

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

数据类型和构造函数:

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
   |                ^^^^^^^^^^^^^^^^^

【问题讨论】:

    标签: haskell instance typeclass definition algebraic-data-types


    【解决方案1】:

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

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

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

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

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

    但 Haskell 使用 模式匹配,因此不完全清楚重用同一个变量意味着什么,特别是因为不是每个类型都是 Eq 的实例。

    【讨论】:

    • 感谢 Willem,阐明了数据类型中参数的使用。
    • 我认为应该删除实例上下文,而不是拆分。
    • @DanielWagner: aaarrggh...是的。谢谢!
    【解决方案2】:

    您可能希望利用您的 helper 函数将两个 MyNums 转换为 Rationals 以便您可以比较它们:

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

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

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

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

    【讨论】:

    • 如何以及何时在实例 Eq 中调用助手?你能解释一下那行代码吗?顺便说一句,您的回答非常简洁明了。谢谢。
    • @stcol 关键行是x == y = helper x == helper y,这意味着:只要您有两个x,y 类型为MyNum 的值,要计算x==y,您就可以计算helper x == helper y,即应用助手x 和 y 并比较结果。
    猜你喜欢
    • 1970-01-01
    • 2021-12-13
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    相关资源
    最近更新 更多