首页 > 解决方案 > Instance Eq 在 Haskell 中不起作用

问题描述

所以我得到了以下数据类型,我必须编写一个代码来检查一个元素是否在列表中(我认为我做对了)。在此之后,我必须声明实例 Eq,如果我的两个金额列表相等,它将为 True。我应该使用我之前编写的元素代码。有人可以告诉我我做错了什么吗?

   data Amount a = Amount [a] 

element [] _ = False
element (x:xs) y = ( x==y) || element xs y

instance Eq (Amount a) where 
      Amount xs == Amount ys = element xs ys && element ys xs

这是我收到的错误消息

 • Couldn't match expected type ‘a’ with actual type ‘[a]’
      ‘a’ is a rigid type variable bound by
        the instance declaration at Probeklausur1.hs:43:10-22
    • In the second argument of ‘element’, namely ‘ys’
      In the first argument of ‘(&&)’, namely ‘element xs ys’
      In the expression: element xs ys && elementS ys xs
    • Relevant bindings include
        ys :: [a] (bound at Probeklausur1.hs:44:27)
        xs :: [a] (bound at Probeklausur1.hs:44:14)
        (==) :: Amount a -> Amount a -> Bool
          (bound at Probeklausur1.hs:44:17)
   |
44 |       Amount xs == Amount ys = element xs ys && elementS ys xs     |                                           ^^

Probeklausur1.hs:44:49: error:
    • Variable not in scope: elementS :: [a] -> [a] -> Bool
    • Perhaps you meant ‘element’ (line 40)
   |
44 |       Amount xs == Amount ys = element xs ys && elementS ys xs     |                                                 ^^^^^^^^

标签: haskellinstance

解决方案


我们先分析一下类型element

element [] _ = False
element (x:xs) y = ( x==y) || element xs y

我们看到第一项是一个列表[a](基于[](:)数据构造函数)。此外,我们知道第二个项目的类型是列表元素的类型,所以a,并且因为我们调用x == y,所以必须有一个Eq a约束。所以我们得出:

element :: Eq a => [a] -> a -> Bool

对于 this: 已经存在一个非常相似的内置函数elem :: Eq a => a -> [a] -> Bool,因此最好改用这个。

但是现在让我们看一下实例声明:

instance Eq (Amount a) where 
    Amount xs == Amount ys = element xs ys && element ys xs

这里有两个问题:

  1. 我们还需要a有一个Eq类型约束,因为我们需要检查列表的元素是否相同;和
  2. 我们elementxsand调用ys,但两者xs都有ystype [a],所以这不起作用。

因此,我们首先需要一种机制来检查一个列表的所有元素是否出现在另一个列表中。我们可以用这个all :: (a -> Bool) -> [a] -> Bool函数来检查:

allElem :: Eq a => [a] -> [a] -> Bool
allElem xs = all (flip elem xs)

所以现在我们可以这样写:

instance Eq a => Eq (Amount a) where 
    Amount xs == Amount ys = allElem xs ys && allElem ys xs

请注意,上述内容可能仍然不是您想要的,原因有两个:

  1. 没有检查两个列表的顺序,我认为这是故意的;
  2. 如果一个元素在第一个列表中出现多次,那么它不必第二个列表中出现那么多次,只要它至少出现一次就可以了。因此,两个列表的长度可以不同,但​​仍然认为两个Amounts 是相等的。

推荐阅读