When trying to implement dropWhile using foldr the first algorithm that I came up with was this
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' pred = fst . foldr (\cur (acc, xs) ->
if pred cur
then (acc, cur:xs)
else (cur:xs, cur:xs)) ([], [])
While this works, it causes a stack overflow on infinite lists without giving any values. Because I wasn't sure, why this doesn't work, I just played around with the function until I came up with this:
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' pred = fst . foldr (\cur t -> let (acc, xs) = t in
if pred cur
then (acc, cur:xs)
else (cur:xs, cur:xs)) ([], [])
As you can see, the only difference between this one and the first is, that here I'm destructuring the tuple (acc, xs)
inside a let binding instead of destructuring directly inside the function parameter. For some weird reason, this code works on infinite lists.
If anyone has any idea why this behaves as it does, please let me know.
Let expressions in Haskell are lazy:
Let Expressions
(...) Pattern bindings are matched lazily; an implicit ~ makes these patterns irrefutable.
In contrast, lambda abstractions desugar to case
, thus making constructor patterns strict:
Curried applications and lambda abstractions
Translation: The following identity holds:
\ p1 … pn -> e = \ x1 … xn -> case (x1, …, xn) of (p1, …, pn) -> e
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With