Prelude
- Link 1 This post says:
"For a self-recursive function, the loop breaker can only be the function itself, so an INLINE pragma is always ignored," according to the GHC manual
Link 2 This answer describes a method of optimization via in-lining by GHC.
Link 3 This (unrelated) post explains compilers are free to reject explicit inline suggestions anyway. Or perhaps passing the
-O2
flag to the compiler achieves the same effect as the OPTIMIZED VERSION shown below?
Example code
(as seen in Link 2)
--PRE-OPTIMIZED VERSION--
func :: (a -> a) -> [a] -> [a]
func f [] = []
func f [x] = [x]
func f (x:s:xs) = x:(f s):(func f xs)
----OPTIMIZED VERSION----
func :: (a -> a) -> [a] -> [a]
func f = loop
where
loop [] = []
loop [x] = [x]
loop (x:s:xs) = x : f s : loop xs
------Eg-USAGE----------
> mapToEverySecond (*2) [1..10]
[1,4,3,8,5,12,7,16,9,20]
Question
To quote @amalloy's doubts in the comments of Link 2, surely
f
is "still implicitly passed around just as much [as explicitly passing f in the PRE-OPTIMIZED VERSION] by the closure-creating machinery" ?
As an aside, I am reading up on fusion techniques, an alternative approach as described in Link 1, although I am not trying to seek the fastest implementation possible in lieu of idiomatic styles.
Merely curious as to whether/how "where-definition" trick seen in the OPTIMIZED VERSION works (should the compiler decide to inline such a function).
Extra links are most welcome!
\f -> \list -> case list of { …func… }
while the second islet { loop = \list -> case list of { …loop… } } in (\f -> loop)
. The full laziness optimisation in GHC will convert the former to the latter. In general this increases sharing (off
here) and provides opportunities for inlining;INLINE
pragmas work quite differently from C++’sinline
. – Jon Purdy