Suppose I have two functions f :: [a] -> b
and g :: [a] -> c
. I have the following two questions:
If I perform (f &&& g) xs
where xs :: [a]
, and if both f
and g
involve loops, is it possible for the compiler to optimize these two loops into one? (Please note that I am not asking whether some specific Haskell compiler implements this. I want to know whether such a thing is possible.)
Can the traverse
function from Traverse
type class help me have such an optimization with something along the following lines:
traverse (someCombinator f g) xs
We can optimize loops by vectorizing operations. This is one/two orders of magnitude faster than their pure Python equivalents (especially in numerical computations). Vectorization is something we can get with NumPy. Numpy is a library with efficient data structures designed to hold matrix data.
Improved floating-point performance - loop unrolling can improve performance by providing the compiler more instructions to schedule across the unrolled iterations. This reduces the number of NOPs generated and also provides the compiler with a greater opportunity to generate parallel instructions.
It is theoretically possible to optimize this code, but very very difficult, because f
and g
might consume different amounts of the input list. Only when they consume the same amount, or g
always consumes more of the list than f
(or vice versa), would it be possible to perform the optimization. The Halting Problem prevents a compiler from detecting such conditions in complex code.
Only in simple cases, where both f
and g
use foldr
internally, for example, would it be possible to perform trivial optimizations without further introspection.
The traverse
function will not help you here, because there is no reasonable way of implementing someCombinator
(How do you want to transform multiple calls of a
's into one [a]
without serious hacks? And then you are back where you started anyways).
Your only real option is to make f
and g
into folders, so that they have the signatures f :: a -> b -> b
and g :: a -> c -> c
, meaning that the value of b
and c
can be computed incrementally. You can then use \ a -> f a *** g a
to get a folder that you can use in a conventional (right- in this case) fold.
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