2017-12-07 22:25 GMT+01:00 Neil Mayhew <neil_mayhew@users.sourceforge.net>:

[...] The question remains, however: why doesn’t the ghc optimizer spot this fairly obvious loop-invariant in the non-profiled build when it does manage to spot it in the profiled one? In other words, when I make pattern a local definition of parseFilename, why isn’t it treated as a CAF that’s evaluated only once (‘floated to the top level’)?

Because making something a CAF is not always an optimization: If your evaluated CAF uses e.g. hundreds of MB it might be preferable to *not* have it as a CAF, but to to recompute it instead. If I haven't missed something recently, CAFs can't be garbage collected, but I would be happy to be corrected here. :-)

 

Enabling profiling shouldn’t change the meaning of a program.

It doesn't change the meaning, that would really be a desaster, it just changes the performance characteristics. This is still not nice, but not much different from using different levels of optimization: Doing or not doing e.g. strictness analysis might change the space complexity etc.
 

I remember back in the day having to be careful with regexes in Python to make sure they were always precompiled outside of loops and functions, but one of the nice things about Haskell is that one can usually let the compiler take care of this. (Nowadays Python gets around this by caching compiled regexes, but I prefer Haskell’s statically-optimized approach.)

I think totally relying on the compiler for performance is a common misconception, because things are often more tricky than initially thought. In our example: Time vs. space tradeoff, and there is no universally "right" solution.

Cheers,
   S.