take 5 . filter (not . p) . drop 3
In a strictly evaluated language. This would involve iterating over the list three different times. (Kind of not really, since take 5 isn't going to be that expensive.) take 5 . filter (not . p) . drop 3
In a strictly evaluated language. This would involve iterating over the list three different times. (Kind of not really, since take 5 isn't going to be that expensive.)> take 5 . filter (not . p) . drop 3
That doesn't seem to be the case in my testing. Writing this out as an explicitly recursive function sped things up 3x on GHC -O3. (Dropping 10^8, taking 10^7.)
FWIW, I also tested on Rust, Python (PyPy3) and Java (OpenJDK) with iterators, iterators and streams, respectively. Python and Java were about as fast as the manually recursive version, and Rust was two orders of magnitude faster than that. And half of the time in Java was spent boxing, because Java can't reify types away like Haskell.
It's true these are all using opt-in laziness, unlike Haskell's lazy-by-default, so it's not a fair comparison. But I also see little reason to believe that there's "no performance hit", given that that's exactly what I saw.