haskellpattern-matchingpattern-synonyms

How to pattern match the end of a list?


Say I wanted to remove all zeros at the end of a list:

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

This does not work because of the (++) operator in the argument. How can I determine the end of a list through pattern-matching?


Solution

  • There is a function in Data.List to do this:

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

    So you can drop the trailing zeros with

    dropWhileEnd (== 0)
    

    Another, very similar, function can be implemented like this:

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

    dropWhileEnd2 p has exactly the same semantics as reverse . dropWhile p . reverse, but can reasonably be expected to be faster by a constant factor. dropWhileEnd has different, non-comparable strictness properties than the others (it's stricter in some ways and less strict in others).

    Can you figure out circumstances under which each can be expected to be faster?