1

如果我有:

data Container a = Node a | End a | Container a

如果我想编写一个可以查看 Container a 元素列表并执行列表差异的函数,我该怎么做才能明确告诉编译器这个抽象数据类型允许相等?

我以为会是:

compare::Eq (Container a) => Container a -> Container a -> Bool
compare a b
           | a == b = True
           | a /= b = False

但它抱怨 Eq 语句不正确,因为它无法推断 (Eq (Container a)) 因使用 '=='

编辑它似乎在我的抽象数据类型中派生 (Eq) 是允许这样做的唯一方法。有人可以确认吗?

EDIT2 包括推导 (Eq) 后:

test:: [Container a] -> Container a -> Bool
test list element = elem element list

“没有 (Eq a) 的实例”

4

2 回答 2

6

通知编译器此类实例的最简单方法是使用deriving子句。在这种情况下,

data Container a = Node a | End a | Container a deriving (Eq)

也可以Eq手动给出一个实例,例如下面说如果 aContainer包含可以测试相等性的元素,那么Container也可以测试相等性。

instance Eq a => Eq (Container a) where
    (Node a)      == (Node b)      = a == b
    (End a)       == (End b)       = a == b
    (Container a) == (Container b) = a == b
    _             == _             = False

这与给出的定义相同deriving,因此不必像以前那样输入定义,但是如果想要更复杂的定义,Eq则必须做类似的事情。

一旦你有了Eq容器的实例,你就可以写:

compare :: Eq a => Container a -> Container a -> Bool
compare a b | a == b = True
            | a /= b = False

(关于这个函数的两件事:它实际上完全没有意义,因为它与 相同(==),并且应该otherwise用作警卫中的最后一个替代方案。)

这些基本上是仅有的两个选择。虽然还有第三种方法,本质上是两者的结合:使用 GHC 扩展StandaloneDeriving

deriving instance Eq a => Eq (Container a)
于 2012-09-08T13:43:30.193 回答
1

至于“没有(Eq a)的实例” - 你的类型是错误的。

test:: [Container a] -> Container a -> Bool

该类型表示您可以比较任何错误的容器。您当前的实例仅适用于具有可比较元素的容器。所以你应该写

test:: Eq a => [Container a] -> Container a -> Bool
于 2012-09-08T15:30:33.537 回答