Hacker News new | ask | show | jobs
by theamk 2570 days ago
It's interesting that any time I read about Haskell, I realize most of the features can be found in other languages.

Functional programming and lazy evaluation are common in Apache Spark ("analytics engine for large-scale data processing."). You cannot write a good pipeline if you think in terms of imperative language.

Non-nullable types can be found in Java (@NonNull) and in C++ (references). C++17 got std::optional type.

We have languages without inheritance, like Go, Rust and so on.

Errors-as-values are pretty common as well (C++'s boost had boost::error code for a while now, and of course there is Go again)

Even monads find themselves in other languages -- using org.apache.spark.rdd.RDD is pretty close to IO monad.

I find this an unfortunate downside of many Haskell tutorials -- they often claim there are unique features that are present in Haskell only, but on the closer inspection, it turns out those features are present / can be trivially added in many other languages as well

4 comments

Hey that was kind of my point -- but I think you have it in reverse, Haskell has had a lot of this stuff for a long time (as in most of them since it's inception), and it's trickling down to other languages now.

But to make some concrete counter points:

- Apache Spark is not a general purpose programing language (you're totally right about FP and lazy evaluation being important in DAG-land of course)

- "Non-nullable types can be found in Java", yeah except them being the default is the big innovation, along with the recognition of the problem, and facilitation of the worldview that recognizes the issue. Optional didn't show up until a few years ago (Java 8?), first class functions weren't a thing without subclassing till around then too, Function references, Functional interfaces, etc. I'm less familiar with C++ and it's commendable that it's adopting new things and people are moving forward, but it's basically the gold standard of footguns with type-system scopes attached (again I don't write C++ on a daily basis and haven't felt just how much better the new editions are).

- Go and Rust learned from Haskell, Rust heavily so. BTW these days I'm more and more of the opinion that Rust is the one more worth praising of the two

- What go does is kind of error as values, but it's also kind of not -- I mean a near complete lack of use of exceptions at all. The distinction is subtle, but coding to always handle the error case (because it is the result) is different from having a sometimes-present error code that you sometimes check.

- Again, you're right that Monads are everywhere -- Haskell didn't invent the concept, but it is one of the places you can go to see it actually used functionally and learn from what people are doing with it (never mind all the novel papers).

Haskell is one of the few places that all these features come together to form a coherent whole.

> Functional programming and lazy evaluation are common in Apache Spark

Spark ain't a language, it's an engine. Anyhow, you could make the point for lazy evaluation in stream libraries in many languages. It's not really comparable to having this as a first class citizen in the language, just like Guava didn't make Java7 equal to Java8.

> Non-nullable types can be found in Java (@NonNull) and in C++ (references). C++17 got std::optional type.

The reason people talk about it isn't about having non nullable types, it's about not having nullable types (or, at least, not having them as a default).

> We have languages without inheritance, like Go, Rust and so on.

I don't believe not having inheritance is a language feature. People may say that inheritance was a mistake and that languages without it are better off, but you will rarely hear about no inheritance being a feature of a language.

> Errors-as-values are pretty common as well (C++'s boost had boost::error code for a while now, and of course there is Go again)

Haskell has an error system. Errors as values are a pattern enabled by other things of the language (ADTs, functors/monads), but not having errors is not a Haskell feature. Elm would be a better example of this.

> Even monads find themselves in other languages

See above point about first-class things in a language.

Your analysys about features is misguided because languages aren't things that can be compared feature by feature. They are a coherent set of things that produce a specific dev experience. Haskell is offering a specific experience that people enjoy, and therefore, people talk about it, and some other languages tend to adopt some of the features in an attempt to reproduce the experience.

This is a catch-22 of asking people to explain the advantages with simple side-by-side examples. If you want an example of something truly unique to Haskell, we'd have to talk about e.g. using the cataM function in a kind-polymorphic way. But you'd have to get a certain depth into the Haskell mentality before you could understand why that's useful or valuable. So we talk about the simple examples - but lots of languages solve those simple examples with limited/ad-hoc/special-case versions of things that Haskell does with more powerful general features. https://philipnilsson.github.io/Badness10k/escaping-hell-wit... has some examples of this phenomenon.

Apache Spark could probably never have been created without using the only other mainstream language with higher-kinded types (Scala) - now that the design has been proven a lot of it has been rewritten in a verbose Java style, but I doubt the work to come up with that design could have been done while thinking solely in Java.

Working without inheritance is only practical if you have typeclass derivation. Rust and Scala approximate this with macros. I don't think any other mainstream language has that functionality at all.

Non-nullable types and errors-as-values are only practical if you have higher-kinded types. (Rust has an ad-hoc macro that works for a handful of error-as-value types, but you can't write the general monadic library functions that you'd want to work with them properly).

Haskell is not entirely unique, but it's pretty close. The only other remotely mainstream language that has the combination of higher-kinded types and typeclass derivation (ish) is Scala, and even then you'll eventually get bitten by the lack of kind polymorphism.

There are no tutorials that claim these features are unique to Haskell or that they cannot be added to other languages.