Well, it turns out that I defined this function in my program code:
st_zipOp :: (a -> a -> a) -> Stream a -> Stream a -> Stream a st_zipOp f xs ys = St.foldr (\xr -> st_map (fx) r) xs ys
Does what it seems. It fastens (applying the operator several times, yes) two elements of type Stream a , which is a list type, using an internal operator of type a . The definition is pretty simple.
As soon as I defined the function this way, I tried this other version:
st_zipOp :: (a -> a -> a) -> Stream a -> Stream a -> Stream a st_zipOp = St.foldr . (st_map .)
As far as I know, this is exactly the same definition as above. This is just a meaningless version of the previous definition.
However, I wanted to check if there was any performance change, and I found that, indeed, the pointless version made the program a little worse (both in memory and in time).
Why is this happening? If necessary, I can write a test program that reproduces this behavior.
I compile with -O2 if that matters.
Simple test case
I wrote the following code, trying to reproduce the behavior described above. This time I used lists, and the performance change was less noticeable, but still existed. This is the code:
opEvery :: (a -> a -> a) -> [a] -> [a] -> [a] opEvery f xs ys = foldr (\xr -> map (fx) r) xs ys opEvery' :: (a -> a -> a) -> [a] -> [a] -> [a] opEvery' = foldr . (map .) main :: IO () main = print $ sum $ opEvery (+) [1..n] [1..n] where n :: Integer n = 5000
Profiling results using opEvery (version of explicit arguments):
total time = 2.91 secs (2906 ticks @ 1000 us, 1 processor) total alloc = 1,300,813,124 bytes (excludes profiling overheads)
Profiling results using opEvery' (free version):
total time = 3.24 secs (3242 ticks @ 1000 us, 1 processor) total alloc = 1,300,933,160 bytes (excludes profiling overheads)
However, I expected both versions to be equivalent (in every sense).