
Hi. Simon Peyton-Jones wrote:
| I've definitely run into the odd other case where point-freeing | a bit of code messes with the complexity.
That should not happen -- except for the state-hack. Which is this:
Consider f1 :: Char -> IO () f1 = \c. let i = ord c in \s. print i s
Here s::State World. Is this equivalent to f2 = \c.\s. print (ord c) s
The latter is very much more efficient than 'f1', because it doesn't build an intermediate lambda. This matters a lot in I/O-intensive programs. But if 'f' is called thus:
forever (f 'w')
then (ord 'w') is computed once for each call of f2, but is shared among all calls to f1. And that can make a big difference too.
Thanks for the explanation. State World here really means the IO and ST monad, not the State monad, right? Compiling with -fno-state-hack actually does actually lead to both versions (the point-free and explicit) being equally fast (14.4s instead of 15.2s resp. 14.0s). Though I am not sure why. Running in profiled mode makes all difference vanish. I tested this on an Intel(R) Pentium(R) 4 CPU 3.00GHz and got the reported speed difference there. Using instead an AMD Athlon(tm) 64 Processor 3800+ I got no difference even without using -fno-state-hack.
I have no idea whether this is playing a role in the example you are discussing -- my guess is not, and there may be another performance bug lurking. So eliciting a small demo would be great.
I am sorry, I completely failed to do that. The parser builds up a data structure from several data types using memoization. Any significant simplification of the code base reduced the performance gap until it quickly disappeared. Alexander