如何模式匹配列表的结尾?

时间:2016-03-14 23:28:55

标签: haskell pattern-matching pattern-synonyms

说我想删除列表末尾的所有零:

removeEndingZeros :: (Num a, Eq a) => [a] -> [a]
removeEndingZeros (xs ++ [0]) = removeEndingZeros xs
removeEndingZeros xs          = xs

由于参数中的(++)运算符,这不起作用。如何通过模式匹配确定列表的结尾?

2 个答案:

答案 0 :(得分:7)

Data.List中有一个功能可以执行此操作:

dropWhileEnd :: (a -> Bool) -> [a] -> [a]
dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []

所以你可以用

删除尾随的零
dropWhileEnd (== 0)

另一个非常相似的功能可以像这样实现:

dropWhileEnd2 :: (a -> Bool) -> [a] -> [a]
dropWhileEnd2 p = foldr (\x xs -> if null xs && p x then [] else x : xs) []

dropWhileEnd2 preverse . dropWhile p . reverse具有完全相同的语义,但可以合理地预期通过常数因子更快。 dropWhileEnd具有与其他人不同的,不可比较的严格属性(在某些方面它更严格,在其他方面更严格)。

你能指出每种情况可以更快的情况吗?

答案 1 :(得分:6)

在标准Haskell中,您无法在列表末尾进行模式匹配。由于列表的定义方式,访问列表末尾需要花费时间线性列表的长度。由于在最坏的情况下你不能在没有两次遍历的情况下丢弃尾随零,显而易见的解决办法很好 - 从列表的反面删除前导零,然后再次反转以恢复原始顺序:

removeEndingZeros = reverse . dropWhile (== 0) . reverse