检查空列表时,为什么必须将元素类型的列表设为Eq

时间:2016-03-21 14:47:07

标签: haskell

以下reverse'函数的类型为Eq t => [t] -> [t]

reverse' list | list == [] = []
              | otherwise  = (reverse' listTail) ++ [listHead]
                where (listHead : listTail) = list

为什么列表中的元素必须是类型类Eq的成员?我没有比较相等的元素,但它们包含在列表中。

在我的直觉中,t的列表必须是等同的,但t本身并不是。

2 个答案:

答案 0 :(得分:8)

这是因为如果我们可以比较它们的元素是否相等,我们只能比较一般的列表是否相等。也就是说,在一般情况下,除非我们能够解释[a, b, c] == [d, e, f],否则没有真正的方法来解释a == d

这反映在列表上的(==)类型中,这些类型对您的案例和更广泛的案例都有效:

 (==) :: (Eq a) => [a] -> [a] -> Bool

但是你不想真正地将相等列表与另一个列表进行比较,你只想检查一个列表是否为空,所以

 null :: [a] -> Bool

是一个更好的选择。并且它没有那个等式约束,因为它只是在列表的结构上使用模式匹配,这从不需要类型类约束。

  null :: [a] -> Bool
  null [] = True
  null (_ : _) = False

在你的情况下,更好的方法就是自己做模式匹配,毕竟,你已经是一个模式了!

reverse' [] = []
reverse' (listHead : listTail) = (reverse' listTail) ++ [listHead]

这与惯用的Haskell更接近,因为验证它不会崩溃可以由编译器轻松完成,我们已经以一种可以检查的方式详尽地涵盖了所有情况。在您的版本中,为了验证代码是否可行,我们必须通过代码跟踪两条路径,并确保空列表永远不会在我们完成该模式匹配的分支中结束。这只是一个小问题,但它很快就会陷入困境。

答案 1 :(得分:5)

因为(==) :: Eq a => a -> a -> Bool仅适用于Eq的实例,[]只是Eq的实例,如果其元素是Eq的实例:< / p>

instance (Eq a) => Eq [a] where
    ...

相反,使用null :: [a] -> Bool或模式匹配来检查列表是否为空:

reverse' [] = []
reverse' xs = ...