Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> This is an explainabrag

My goal here was to show that standard Haskell boils down to a small set of features, therefore it's a simple language. Surely, "simple" does not imply "good" (Brainfuck is also simple), so I then assert that the combination of features that Haskell consists is fertile soil for writing maintainable and performant code.

> languages without these features can also have "clean, maintainable code"

Some people may prefer ML modules to type classes, sure. As to the other features, I have a hard time imagining a clean codebase in a language without some form of polymorphism, first class functions, and algebraic data types. (And lazy evaluation is a great addition to the list). Perhaps there are other sweet spots in the language design space, but I have not seen them yet.

> and nothing about this list implies "runs fast."

GHC is good at optimising this kind of code. https://stackoverflow.com/a/35038374

> Is a memory leak meant to be the "worst sort of bug" or a "security vulnerability?"

It's often hard to debug, and it means that the program can't be running for a long period of time. I suppose I should've used a better example, e.g. "use-after-free", to highlight the dangers of manual memory management.

> Haskell is particularly prone to "space leaks" due to its laziness.

Space leaks are benign compared to memory leaks in that the memory is eventually freed. That said, I'd be happy to have some sort of static analysis to prevent them.

> Why bring up Cyclone and not, say, Swift? Or is Swift meant to be included in "garbage collected languages?"

Swift relies on automatic reference counting, which is similar to garbage collection in that it isn't done by the programmer and has a runtime performance cost. Remarkably, it seems to be worse on both accounts: the cost of decrementing/incrementing these counters is very real, and handling reference cycles is not automatic (you need to carefully use weak references).

Here's an interesting discussion of RC vs GC in context of .NET https://blogs.msdn.microsoft.com/brada/2005/02/11/resource-m...

Rust, on the other hand, offers a static analysis with no runtime performance overhead to manage memory safely.

> dynamically typed languages with static type checking

You're talking about gradually typed languages. Sure, these are not unityped, but they also not purely dynamically typed (you said it yourself – they have static type checking). Perhaps that's just a difference between our uses of the term "dynamically typed" and we don't have a true disagreement here?

By the way, Haskell can do that too, we have the `Dynamic` type right in the `base` package.

> This read like a troll piece.

I'm sorry.



> the cost of decrementing/incrementing these counters is very real

Only true if you use pervasive reference counting, with atomic updates. Swift essentially does this, but other languages don't.

One of the reasons why it makes sense to single out tracing GC (as opposed to RC) is that it's essentially a package deal; your whole program needs to be structured to use memory as essentially an in-RAM database, where every single object or reference can be traced after the fact at some arbitrary time in the future. (There are reasons to do this in some cases, even in 'low-level' languages which are not ordinarily garbage collected - see e.g. the use of "entity component systems" in such languages - but it's obviously not a generally-appropriate solution in any real sense!). RC is self-contained, and it need not even be locally inefficient.

> You're talking about gradually typed languages.

Interestingly, gradual typing does seem to end up with a "worst of both worlds"-type situation - the dynamic tag checks and conversions that have to be inserted at every boundary between statically- and dynamically-typed parts of the program introduce pervasive inefficiency, which is only resolved when static typing is used essentially throughout.


The term for languages like Swift, Java, and Haskell is "obligate GC". The cost of obligate GC is only superficially just the poor memory locality, interruptions, and bad citizenship -- worse is that the power of destructors is denied you, and with it the power to automate managing every other kind of resource.


> worse is that the power of destructors is denied you, and with it the power to automate managing every other kind of resource.

These are orthogonal concerns. Plenty of languages without GC do not have good support for ARM (e.g. C), and a GCed language can still have good support for ARM (e.g. monadic regions in Haskell). C++ is really the only language that conflates the two, and IME its RAII style is overrated in practice (there are a lot of rules you have to follow to avoid leaking, and for many of them you get very little warning if you break it).


> I have a hard time imagining a clean codebase in a language without some form of polymorphism, first class functions, and algebraic data types

You don't have any definition of 'clean', so maybe you mean something precise or maybe you don't, but I have seen clean codebases in all kinds of languages - C, C++, Go, Java. The language doesn't dictate whether your code is clean or not, the programmer does.


Bad programmers will write bad code in any language, but in some languages even the best programmers will struggle to write good code. E.g. I've found even the best C tends to look quite cluttered, because the lack of first-class functions forces the programmer to thread state through "by hand", and the lack of polymorphism means the programmer can't clearly separate the what from the how but has to interleave the two. (Indeed I would say bad C can sometimes look superficially cleaner: things like using global variables for state remove some of the clutter, but ultimately the cure is worse than the disease)




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

Search: