3 ms·
I’ve had a Haskell program fail in exactly the same way, though - removing a debug statement caused a program to start crashing - even though the lazy functions
by jes5199 9y ago
I’ve had a Haskell program fail in exactly the same way, though - removing a debug statement caused a program to start crashing - even though the lazy functions were completely pure.
We had a numeric counter that was enumerating the frame number of a simulation. When we removed the debug statement, we didn’t realize that no other code ever evaluated the counter - so instead of resolving each X+1 into an integer, Haskell kept it as a ever-growing nested series of unevaluated thunks: 1+1+1+1+1+1+1+1+1+1+... , and our efficient little program started filling up all its available RAM and crashing.
- taeric 9y agoJust, wow. I'm curious if there are mechanisms that could guard against growing strings of unevaluated thunks. Would be an interesting GC problem. One where you free up space by forcing a maximum depth of unevaluated space. (You'd obviously have to treat any "infinitely extra" computations versus the "do this on top of that" ones. But that shouldn't be undoable, should it?)
- jpittis 9y agoRelevant blog post and HN comment thread about tracking space leaks in Haskell. https://news.ycombinator.com/item?id=10263964 https://news.ycombinator.com/item?id=10263964
- zenhack 9y agoYeah, this is Haskell's biggest footgun by far. The language gives you tools to control evaluation order (including some neat libraries that let you parallelize things without much disruption to the logic of your program), but there are no silver bullets. A good rule of thumb is to by default mark fields for basic types like Int, Bool, etc. as strictly evaluated, and leave larger structures (trees, lists, etc) lazy. But you still need to be careful. The compiler trying to silently fix things is probably a bad idea. The current behavior is at least easy to understand; I'd hate to have a program that's working because the compiler could figure out that it could make something strict, and then I bump something mostly unrelatrd such that the optimizer can't be sure anymore, so I get a space leak. Also, unintended evaluation can potentially cause high memory use as well (e.g. [1..1000000]), so the compiler also has to be careful about introducing excessive memory use. The compiler does do some strictness analysis, but it's a hard problem. I like the way idris does things -- strict by default, laziness controlled by the type system, and some nice support for automatic coercions.
- taeric 9y agoTo be clear, I was not voting for the compiler to do this, but the runtime. It should be instrumented and it would likely be a round trip process sometimes, with people tweaking how it does things.
- jpittis 9y agoFor those not in the know, this is called a “space leak”.
- tel 9y agoHaskell generally doesn’t consider computation a side effect which is a bit tragic.
- setr 9y agoIf no one ever references the counter, and its known to be pure, then shouldn't the compiler just remove it entirely?
- kerkeslager 9y agoYeah, purity doesn't always make laziness easy to reason about. But it usually does.