以下reverse'
函数的类型为Eq t => [t] -> [t]
:
reverse' list | list == [] = []
| otherwise = (reverse' listTail) ++ [listHead]
where (listHead : listTail) = list
为什么列表中的元素必须是类型类Eq
的成员?我没有比较相等的元素,但它们包含在列表中。
在我的直觉中,t
的列表必须是等同的,但t
本身并不是。
答案 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 = ...