【问题标题】:Problem with Eq in Haskell for comparing ListsHaskell中用于比较列表的Eq问题
【发布时间】:2021-03-18 05:07:22
【问题描述】:

我自己在 Haskell 中实现列表,但是在比较两个列表是否相等时遇到了一点问题,

data List a = Void | Cons a (List a) -- deriving (Show, Eq)

instance (Eq a) => Eq (List a) where
  (==) a b = equalHelp a b

equalHelp :: (Eq a) => List a -> List a -> Bool
equalHelp Void Void = True
equalHelp a Void = False
equalHelp Void b = False
equalHelp (Cons a b) l = if (myElem a l) then (equalHelp b l) else False

myElem :: (Eq a) => a -> List a -> Bool
myElem a Void = False
myElem a (Cons c d) = if (a == c) then True
                      else myElem a d

例如,如果我有

l1 = (Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 Void)))))

如果我执行l1 == l1,则不是打印True,而是打印False。 我错过了什么?

【问题讨论】:

  • (1) 如果你取两个相等的列表并从其中一个中删除第一个元素,它们将不再相等。 (2) 无论如何,你不需要myElem来实现(==);只需在每一步直接比较列表标题即可。
  • if A then B else FalseA && B 相同。
  • if A then True else BA || B 相同。
  • @molbdnilo 是的。我当时还没有读到这么远。 :)

标签: haskell methods equality algebraic-data-types custom-data-type


【解决方案1】:

您的equalHelp 实现了isSubset subset ofSet 谓词——几乎,除了它总是滑入空的第二个列表案例然后失败。

相反,停止对单例情况的递归:

isSubset :: (Eq a) => List a -> List a -> Bool
isSubset Void Void = True
isSubset a Void = False
isSubset Void b = False
isSubset (Cons a Void) l = if (myElem a l) then True           else False
isSubset (Cons a b)    l = if (myElem a l) then (isSubset b l) else False

由于前面的子句,您的第二个子句假定 a 是一个非空列表。但最好是每个子句的假设都公开明确并且模式是互斥的(如果这样做不会使我们的代码过于冗长,从而降低可读性)。因此,我们把它写成

isSubset :: (Eq a) => List a -> List a -> Bool
isSubset Void         Void  =  True
isSubset (Cons _ _)   Void  =  False
isSubset Void  (Cons _ _)   =  False
isSubset (Cons a Void)  l   =  myElem a l
isSubset (Cons a b)     l   =  myElem a l && isSubset b l

这里故意留下一个错误,即代码的痕迹。其中一个子句是错误的:空集是any set 的子集。因此,处理空集作为第一个参数的两个子句可以合并为一个子句。

我们还使用了代码简化

if A then True else False   ===   A
if A then B    else False   ===   A && B

在此重写。还有

if A then True else C       ===   A || C

您可以使用它来简化您的 myElem 定义。


纠正代码的另一种方法是将其视为定义列表的相等性直到元素的排序。按照 cmets 中的建议,在每个递归调用中也删除第二个参数的 head 元素不会起到作用,因为我们需要删除找到的元素,该元素可能不是 - 也可能不是 - head 元素。这可能不是很简单,也不是很有效,特别是如果您还选择允许元素的多样性。在这种情况下,最简单的方法就是定义

equalUpToOrderingWithMults a b =
    isSubset a b  &&  isSubset b a

最直接的方法是放弃 myElem 调用,而是在递归的每个步骤中仅比较两个参数列表的头元素,以获得“正常”,可以说,相等的概念。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-28
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多