4 ms·
Pardon me if this is dense, but I don't see how laziness prevents you from examining f and g separately.
by theCodeStig 6y ago
Pardon me if this is dense, but I don't see how laziness prevents you from examining f and g separately.
- imtringued 6y agoIncredibly simplified example: f generates a list of 100 expensive calculations each taking 10 seconds. g filters out every second element. Printing out the result of g(f(a)) is 2 times faster than printing just f(a). In a non lazy language f(a) and g(f(a)) would take roughly the same amount of time. In this example the expensive calculations take much longer than printing the output to the terminal. (no nitpicking please)
- jose_zap 6y agoAnd how is that more difficult to reason about? The asymptotical performance is exactly the same for strict and non-strict languages. The performance can only be at most f + g. It may take less time in a lazy language, how is that difficult to reason about, and why would you care if it runs faster?
- lmm 6y agoThe speedup is invisible in the code, and so when it stops working you can't tell whether it was meant to be working. The cornerstone of pure functional programming is that you can refactor fearlessly because of referential transparency, but if your program has invisible magic performance boosts in it then you lose that ability, because you never know when one of your refactorings will eliminate one of those performance boosts that turned out to be load-bearing. Imagine you've got a performance problem because f + g used to take x time but now takes 4x. You start trying to break down the problem, and you see that f takes 2x time and g takes 2x time. You check out the old tag where f + g takes x time and you discover that f takes 2x time and g takes 2x time. Where do you even go from there?
- jose_zap 6y agoWell, you would tackle the problem in the same way you do in a strict program. If both functions take the same time in isolation, it would make sense to review both functions performance to improve the whole. How is that difficult to reason about? How did laziness made it impossible? If anything, it can make things run faster, but if something is already slow, you just start by looking at the slowest function. You don’t even have to guess, the Haskell profiler will tell you what function that is, even with laziness involved!
- lmm 6y ago> If both functions take the same time in isolation, it would make sense to review both functions performance to improve the whole. How is that difficult to reason about? How did laziness made it impossible? Because the slowdown didn't happen in either function. f still takes the same time it used to. g still takes the same time it used to. But somehow the composition has gotten significantly slower. Both functions may be slow when run in isolation, but it's impossible to tell whether one or both is "supposed to" be slow. Profiling and looking at the slowest function can easily lead you on a wild goose chase here.
- jose_zap 6y agoIn your g(f(x)) composition example you said that g would be filtering out eveery other record, that could only make thiings faster, not slower. Could you formulate an example where the composition would be asymptotically slower only for lazy languages? As I said before, laziness is actually an optimization strategy. If anything, it can only make the composition faster than it would be in a strict language (although rarely so)
- lmm 6y ago> Could you formulate an example where the composition would be asymptotically slower only for lazy languages? No; we both know no such thing exists. The same code will always be asymptotically faster in a lazy language. The problem is that lazy languages (or at least, the one lazy language in widespread use) encourage a style of code that would be asymptotically slower if written in a strict language. In a strict language, a function is slow or fast, and a slow function is always a problem - which means performance is easy to reason about. In a lazy language, a slow function is not necessarily a problem, depending on how it's used, and so you can't understand performance without understanding the whole program. An unreliable optimisation can be worse than no optimisation at all. Worst practices should be hard. In theory an extremely vigilant development team could always write code that would be fast if executed strictly, and therefore guarantee no performance problems, but this would require an enormous manual effort since the language doesn't help you with it at all.