[Haskell-cafe] Most elegant funciton for removing adjacent
duplicates from a list using foldl and foldr
wren ng thornton
wren at freegeek.org
Sun Mar 15 20:17:24 EDT 2009
R J wrote:
> I need to write an implementation using foldl, and a separate implementation using foldr, of a function, "remdups xs", that removes adjacent duplicate items from the list xs. For example, remdups [1,2,2,3,3,3,1,1]= [1,2,3,1].
>
> My approach is first to write a direct recursion, as follows:
>
> remdups :: (Eq a) => [a] -> [a]
> remdups [] = []
> remdups (x : []) = [x]
> remdups (x : xx : xs) = if x == xx then remdups (x : xs) else x : remdups (xx : xs)
>
> This code works, but it has three cases, not usual two, namely [] and (x : xs).
You should take a look at the page on declaration style vs expression
style:
http://haskell.org/haskellwiki/Declaration_vs._expression_style
At the risk of doing homework, it is always the case that you can
decompose complex pattern matching into basic pattern matching (which
for lists means it always has two cases, since list has two
constructors).[1]
remdups [] = ...#1
remdups (x:[]) = ...#2
remdups (x:(xx:xs)) = ...#3
== {desugar pattern-matching into case}
remdups = \a -> case a of
[] -> ...#1
(x:[]) -> ...#2
(x:(xx:xs)) -> ...#3
== {desugar case into case}
remdups = \a -> case a of
[] -> ...#1
(x:b) -> case b of
[] -> ...#2
(xx:xs) -> ...#3
This transformation explicitly gives a name to the second argument of
the first (:) which is beneficial since it means you don't need to
allocate a new one that's identical to the old one in order to pass to
the recursion. For the Then we know x==xx therefore (x:xs) == (xx:xs),
for the Else we need (xx:xs), in both cases we already have an (xx:xs)
laying around, namely b.
If you want to give a name like this without manually desugaring the
case statements yourself, then you can use an as-pattern like (x:
b@(xx:xs)) which will bind the variable b to the value (xx:xs) just like
above.
[1] This would not be true if, for example, the language could express
non-linear terms like in Prolog and other logic languages. Pattern
matching can still be decomposed in such languages, but they need to
introduce unification constraints along with the smaller patterns, to
ensure correctness of the transformation.
--
Live well,
~wren
More information about the Haskell-Cafe
mailing list