Hacker News new | past | comments | ask | show | jobs | submit login

but it's not that different than what you'd get with other programming languages.

Until you have to solve a (maddeningly common) space leak issue. That's a problem unique to lazily evaluated languages (basically Haskell) and is godawful to debug.

It reminds me of solving git problems... you suddenly find yourself having to tear back the abstraction layer that is the language and compiler and start thinking about thunks and so forth.

It's jarring and incredibly frustrating.




I find this response a little ironic because we don't really see complaints about knowing the C runtime and C compiler when performance becomes a problem, which is also jarring and frustrating. But, ultimately, sometimes languages have failings and we need to peek under the hood to figure out how to address it - we're just more comfortable with the relatively common and direct mapping of the C runtime.

I am not experienced enough with Haskell to know whether peeking under its hood involves a more complicated model or not. It might be more frustrating. But its certainly not a unique experience - it's costs are just less distributed over other runtimes.


The C is very straightforward.

Maybe you meant C++? You see no complaint because noone use that anymore. Anything that can be done with an easier language is done with an easier language. The hardcore C++ performance critical code is left to a few veterans, who don't complain.


I don't consider the combination of the C runtime + the machine model straightforward - just less arcane than C++. Consider pipelines and branch prediction and cache lines and it quickly becomes difficult. Granted, those typically become relevant later in the optimization stage than other things.


Pipelines, branch prediction and caching are not part of the C runtime. And unlike Haskell, C makes it easy to look at the assembly for a piece of code, evaluate it for the machine it's running on, and fix these problems when they come up. C is not generally adding additional burdens, especially not ones that a higher-level language like Haskell won't also be adding to a far greater degree.


"we're just more comfortable with the relatively common and direct mapping of the C runtime"

That's a funny way to put it. It's more like the difference between getting results or abandoning the thing altogether due to exploding cost of required effort.


When have you ever had the C runtime be the cause of a performance problem?


I have not because I don't write C professionally. We generally have things that require algorithmic improvements due to the scale - language doesn't matter.

C's model requires you to understand the machine model. Haskell presumably requires you to understand the machine model (but less thoroughly) but understand the compiler's model also. It's a little more but comparable. So complaining only about the Haskell runtime just seems ironic to me.


Writing a custom replacement for malloc is relatively common. Does that count?


I don't see why not, though I wouldn't consider that to be an example of a difficult to diagnose problem in the same vein as lazy evaluation.


Writing a custom replacement for malloc is relatively common.

You... can't be serious. That's common to you?


Yes? From the Wikipedia:

"Because malloc and its relatives can have a strong impact on the performance of a program, it is not uncommon to override the functions for a specific application by custom implementations that are optimized for application's allocation patterns."


"not uncommon" is far far from "common". If you're writing your own malloc replacement you're pretty deep into the weeds of high performance computing. Heck even just deciding to replace the stock implementation with an off-the-shelf replacement puts you in fairly rarified company. I'd wager the vast majority of software written for Linux makes use of the standard glibc allocator.

I expect high performance games are the most common exception, but they represent a fraction of the C/C++ in the wild.

Space leaks in Haskell, on the other hand, are unfortunately relatively easy to introduce.


There is this really great paper about space leaks and arrows: https://pdfs.semanticscholar.org/cab9/4da6e4b88b01848747df82...


> Until you have to solve a (maddeningly common) space leak issue.

Hm, I've been making useful things with Haskell for a couple years including quite a few freelance projects and haven't encountered many space leaks.

Definitely not enough to say they are maddeningly common, or even enough to say they are common.


My experience tracks yours.


here is a method that can help debug space leaks: http://neilmitchell.blogspot.com/2015/09/detecting-space-lea...


I wish the problem was simply detecting and isolating space leaks.

My experience is that actually fixing them can be incredibly difficult, hence my comment about needing to understand the gory details about how the runtime evaluates lazy expressions.

Heck, that post even uses the phrase "Attempt to fix the space leak" as it's often not an obvious slam dunk. Sometimes it even devolves to peppering !'s around until the problem goes away.


> My experience is that actually fixing them can be incredibly difficult

My experience differs, FWIW. If you know where you're creating too many thunks, and you force them as you create them, they don't accumulate.

Making sure you actually are forcing them, and not simply suspending a "force this", is probably the trickiest bit until you're used to the evaluation model.


If you know where you're creating too many thunks, and you force them as you create them, they don't accumulate.

Translation: if you've internalized the way Haskell code is compiled and executes, so that you can easily reason about how lazy evaluation is actually implemented, you can solve these problems.

If not, it devolves to throwing !'s in and praying.

Which is basically my point.

If I don't have a hope of solving common space leaks without deeply understanding how Haskell is evaluated, that's a real challenge for anyone trying to learn the language.


This sounds a bit FUD-ish. Programming in any language involves understanding the evaluation strategy. You seem to be advocating languages that can be used with a level of ignorance or innocence which in practice just isn't possible.

https://en.wikipedia.org/wiki/Evaluation_strategy


I disagree. I contend that most of the time folks ignore the evaluation strategy for eagerly evaluated languages because they're simply easier to reason about. That strikes me as objectively true on its face and I believe most Haskellers would concede that point.

The only time I can think of where that's not the case is when microoptimizing for performance, where the exact instructions being produced and their impact on pipelining and cache behaviour matter. But that's in general far more rare than one encounters space leaks in idiomatic Haskell.

Heck, one just needs to read about two of the most common Haskell functions to hit concerns about space leaks: foldl and foldr. It's just part of the way of life for a Haskeller.

There's simply no analog that I can think of in the world of eagerly evaluated languages that a) requires as much in-depth knowledge of the language implementation, and b) is so commonly encountered.

The closest thing I can come up with in a common, eager language might be space leaks in GC'd languages, but they're pretty rare unless you're doing something odd (e.g. keeping references to objects from a static variable).


You're taking issue with material that is covered in every haskell 101 course worth it's salt (how to understand the properties of foldl and foldr).

We typically don't evaluate the efficacy of a language contingent on someone who is missing fundamental, well-known concepts about the language.

Also, I don't think folks "ignore the evaluation strategy for eagerly evaluated languages". They simply learn it early in in their programming experience.


You're taking issue with material that is covered in every haskell 101 course worth it's salt (how to understand the properties of foldl and foldr).

Oh, I'm not "taking issue". This isn't personal. It's just my observations.

And yes, that one needs to explain the consequences of lazy evaluation and the potential for space leaks to a complete neophyte to justify foldr/foldl is literally exactly what I'm talking about! :)

Space leaks are complicated. And they're nearly unavoidable. I doubt even the best Haskeller has avoided introducing space leaks in their code.

That's a problem.

Are you saying it's not? Because that would honestly surprise me.

Furthermore, are you saying eager languages have analogous challenges? If so, I'm curious what you think those are! It's possible I'm missing them because I take them for granted, but nothing honestly springs to mind.


I didn't claim space leaks aren't a problem. But one has to size the magnitude of the problem appropriately. And one should also cross-reference that with experience reports from companies using Haskell in production.


I think there are different types of space leaks:

- Reference is kept alive so that a computation can't be streamed. Easy to figure out with profiling but fixing them might make the code more complex. Also, if you have a giant static local variable ghc might decide to share it between calls so it won't be garbage collected when you'd expect it.

- Program lacks strictness so you build a giant thunk on the heap. This is probably what you think of when talking about dropping !'s everywhere. I don't find it that difficult to fix once the location is known but figuring that much out can be seriously annoying.

- Lazy pattern matching means the whole data has to be kept in memory even if you only use parts of it. I don't think I have ever really run into this but it is worth keeping in mind.

- I have seen code like `loop = doStuff >> loop >> return ()` several times from people learning haskell, including me. Super easy to track down but still worth noting I guess.

Building giant thunks is the only one where you really need some understanding of the execution model to fix it. 99% of the time it is enough to switch to a strict library function like foldl', though.


> I don't find it that difficult to fix once the location is known but figuring that much out can be seriously annoying.

To be clear, I agree with this. Easy to fix once you know where it is, if you're competent in the language. Occasionally very hard to know that.


> unique to lazily evaluated languages

More precisely, unique to significant use of laziness, which is going to (obviously) be more common in lazily evaluated languages but laziness is supported elsewhere.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: