Reputation: 1107
I'm going through LYAH and have been looking at the use of list comprehension vs map/filters when processing lists. I've profiled the following two functions and included the prof outputs as well. If I am reading the prof correctly id say the FiltB
is running a lot slower than FiltA
(although its only by thousandths of seconds).
Would be right in saying this is because FiltB
has to evaluate x^2
twice?
FiltA.hs
(filter odd
)-- FiltA.hs
module Main
where
main = do
let x = sum (takeWhile (<10000) (filter odd (map (^2) [1..])))
print x
Sat Jul 26 18:26 2014 Time and Allocation Profiling Report (Final)
Filta.exe +RTS -p -RTS
total time = 0.00 secs (0 ticks @ 1000 us, 1 processor)
total alloc = 92,752 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
main Main 0.0 10.1
main.x Main 0.0 53.0
CAF GHC.IO.Handle.FD 0.0 36.3
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 37 0 0.0 0.2 0.0 100.0
CAF GHC.IO.Encoding.CodePage 61 0 0.0 0.1 0.0 0.1
CAF GHC.IO.Encoding 58 0 0.0 0.1 0.0 0.1
CAF GHC.IO.Handle.FD 52 0 0.0 36.3 0.0 36.3
CAF Main 44 0 0.0 0.2 0.0 63.3
main Main 74 1 0.0 10.1 0.0 63.1
main.x Main 75 1 0.0 53.0 0.0 53.0
FiltB
(list comprehensions)-- FiltB.hs
module Main
where
main = do
let x = sum (takeWhile (<10000) [n^2 | n <- [1..], odd (n^2)])
print x
Sat Jul 26 18:30 2014 Time and Allocation Profiling Report (Final)
FiltB.exe +RTS -p -RTS
total time = 0.00 secs (2 ticks @ 1000 us, 1 processor)
total alloc = 107,236 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
main Main 50.0 8.8
CAF Main 50.0 0.1
main.x Main 0.0 59.4
CAF GHC.IO.Handle.FD 0.0 31.4
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 37 0 0.0 0.2 100.0 100.0
CAF GHC.IO.Encoding.CodePage 61 0 0.0 0.1 0.0 0.1
CAF GHC.IO.Encoding 58 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.FD 52 0 0.0 31.4 0.0 31.4
CAF Main 44 0 50.0 0.1 100.0 68.3
main Main 74 1 50.0 8.8 50.0 68.1
main.x Main 75 1 0.0 59.4 0.0 59.4
Upvotes: 3
Views: 268
Reputation: 141
Yes. In this particular case, since n^2
will be odd if and only if n
is odd, you can speed up FiltB to the same speed as FiltA by replacing odd (n^2)
with odd n
.
Like you said, the problem is that for each element n
it's squaring it, checking if that's odd, and if it is, then squaring n
and adding that to the list.
More generally though, the difference is that in a list comprehension, the filtering happens before you map, whereas with map and filter, you can choose the order. So if what you actually want to filter based on is the values in the list after mapping, using map and filter is probably a better choice. You still could do something like this to filter based on whether the squared values are odd:
sum (takeWhile (<10000) [ x | x <- [ n^2 | n <- [1..] ], odd x ])
But that's getting to be pretty hard to read. Map and filter or filtering over the list comprehension explicitly (i.e. filter odd [ n^2 | n <- [1..] ]
) are much better options.
Upvotes: 3