dogweather

dogweather

The complexity of Haskell vs. Elixir's simplicity

I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something…

Haskell reminds me of Java, and even Ruby: it’s got a couple awesome features — strong static inferential typing plus purity. (Ruby has dynamic behavior and “developer friendliness”. Java has “strong” static typing.)

But you can’t just have an excellent type/safety system at the application developer level. To make it work, it’s turtles all the way down. Lens only exists because the native type system makes that (normal) kind of work too hard. And so there’s a seemingly never ending rabbit hole of complexity to learn, all in service of the original goal. The complexity also arises from the need to master implementation details of the Haskell system.

In Ruby, the cost of the “awesome experience” is the need to become an expert test writer, and essentially write every app twice.

In Java, it’s the cost of more and more additions and complex syntax (generics, etc.) to support the original strongly typed goal.

Contrast this with languages which have decided to go another, less pure way: Elixir and Elm.

Learning Elixir, you’ll be blown away by how quickly you can master the whole system and the libraries. I was surprised to realize I was done learning, and I could just spend my time creating business value.

In Elm, they drew a line in the sand at typeclasses — they sealed up the recursively descending rabbit hole of complexity right there.

I do really really like programming in Haskell — at the experienced newbie level. I enjoy being able to refactor and the enforcement of case checking exhaustion (with the correct options enabled.) But would I switch to another simpler ecosystem which provides these same benefits? Yeah.

Most Liked

Qqwy

Qqwy

TypeCheck Core Team

Thank you for your post!

Having programmed in all these languages myself, I find myself disagreeing with you on a couple of points:

First, let me start off with mentioning that every language has its warts. Being a polyglot programmer is, in that regard, both a blessing and a curse: I miss all the features the other languages have, while being slightly annoyed at times at the odd implementation-details or things that exist because ‘it seemed like a good idea at a time’ (and are kept for backwards-compatibility).

I love all the languages (truth be told, some more than others, but it is definitely only a partial order):

  1. About the complexity of the abstractions in Haskell. Yes, you are right, Haskell has mechanisms that can be very difficult to understand. However, I have the strong feeling that this is caused more by a lack of good documentation and tutorials than because ‘abstraction is bad’. Be aware that complexity is not the same as difficulty; often, Haskell turns out to be harder for developers whose mind already contains the leaky abstractions that are present in other languages: For instance, working with recursion is only more difficult than working with loops if you already know loops.

And I have to say: In the last four years, the amount of beginner and beginner-intermediate material about Haskell (and pure functional programming in general) has skyrocketed; probably in part caused by more and more people from other communities looking at the functional paradigm for inspiration.

Haskell’s type system does not exist ‘because it is nice’ (although, of course, tail recursion is its own reward :stuck_out_tongue_winking_eye:), but because it allows you to write code that is as decoupled as can be: For instance, you can write algorithms that work on certain kinds of containers (like: ‘all things that you can add a new element to’) without knowing:

a) what type of actual container it is, nor
b) what things are stored inside.

And because this not only works on containers, but because computational statements are also a ‘container type’, it is possible to leverage the compiler to do insane things, like running a piece of code no longer sequential, but as parallelized as is possible.

That said, Haskell definitely has some rough edges. Most of them are caused by its age (because now we know more than we knew back then), resulting in:

  1. A Prelude with some non-total functions, which basically go against how to program properly in the language.
  2. Some things have very counter-intuitive names, especially when coming from a different programming language (class is for instance used to create a Haskell typeclass. If it had either been called interface or protocol, then a lot more people would have understood it the first time).

Ok, besides my first and maybe most important point, that it is mostly a difficulty to get started for new programmers because of a lack of good tutorials (which seems to be changing), let’s attempt to answer some of your points directly:

Lenses exist because they allow you to decouple what you want to read/change from how it is stored, meaning that you do not have to hard-code your accessors (which in many other languages, you are forced to). In Elixir, we basically have lenses too: It’s called the Access behaviour.

To be honest, I have never found the need to be mindful about the implementation details of Haskell while writing my code, (other than a general sense that Haskell is non-strict in its evaluation, which is not really an implementation detail). The only times you’d dive into this, is when you want to get that last 20% of speed or memory-optimization, which you almost never need. (The root of all evil, etc.)

Ruby is a language that is easy, but definitely not simple: The objects (the proverbial ground) you are holding are shifting under your feet all the time. It is very hard to reason about a Ruby-based system for both users and e.g. computer optimizers. This indeed means a lot of tests need to be written.

It is also the reason that I really like Ruby for writing prototypes, or short command-line-interface tools. But for the same reason, I dislike working with long-running Ruby (on Rails or otherwise) applications: It takes a lot of discipline to keep your code clean in such an unrestricted programming context.

As for Java: Java definitely is somwhere lower on my poset of liked programming languages; mostly because Java’s approach to Growing a Language, and because of its enforced ‘static’ typing.
As one of my colleagues often says: Java is not so much a programming language, as it is a platform to build on top of, because it has such a large ecosystem.

Yes, new Java versions definitely make an attempt at making it a better language :slight_smile: .

Let it be known that Elm is a fully pure language. (Especially since Elm 0.19, since it is now impossible to write your own Native modules)
I still see Elm as ‘Haskell-lite’, and that is meant in the most affectionate way. Because it did not have to care about being backwards-compatible with Haskell’s existing things, it was able to rename a lot of things, and make some different design decisions.

This point is wrong for two reasons:

  1. It has never been said that Elm will not ever support typeclasses. It is definitely true that they are not there right now, but depending on how Elm as a language develops, they might still be added. Evan Czaplicki is more concerned with keeping elm simple (frequently removing languages from the language, which is still possible in its current pre- 0.1 phase). It might very well turn out that typeclasses might greatly simplify some things. But there is definitely a lot of other stuff to implement first. (and building the compiler logic that allows typeclasses to exist, well, that definitely is hard :sweat_smile:).
  2. Elixir has typeclasses. They are called Protocols.

With all that having said, though, currently, I am able to work professionally with Elixir (and Elm), whereas Haskell hasn’t found a place in my professional workspace yet.
But this is probably because we are mostly a web-development shop.
The reason then that we use Elixir, is because it is a very pragmatic language (as is Erlang; which, as Joe Armstrong has repeatedly said, only ended up as a functional language ‘by accident’ because it was the most practical solution for the problem that Ericsson had at the time).

In the end, all programming languages are a tool. Programming in Haskell (or in any language) is not the goal, but a means to build something truly marvellous.

25
Post #2
gon782

gon782

I’ll add that OCaml’s guiding light has never been ergonomics and you can feel it when you use it.

Tons of the features that make Haskell compilation slower (solved by using ghcid, by the way, for anyone who hasn’t used Haskell ever / in a long time) are there to make your development better. Even the simple things like free ordering of definitions, partial application of type constructors without extra libs, top-level pattern matching, etc… It’s death by a thousand cuts even before you get to inevitably missing typeclasses and other big features.

As a general comment on a lot of things in threads like these that toss around “practical” and “pragmatic”:

It’s an interesting sort of accepted way to argue in favor of less rigorous methods and languages. Some would argue that having more static verification is more practical and pragmatic, but these words are almost always used as “Well, those are not the bugs that happen in my code [read: that I remember]”. My reality looks a lot different. There’s very little that’s practical about not having more static guarantees and I miss it everywhere I don’t have it.

It’s a matter of degree too. When I saw what people could do with dependent types I wanted them immediately. So I tried Idris and just didn’t get how to use them. I later tried again and got just a little bit closer to getting it. I’m not “with it” enough to sit down and think in dependent types, but I definitely want to be and I definitely will be. Because it just adds more static guarantees, even on the value level (by proxy of being able to have the value level in the type level).

Let’s face it: Humans are the best at programming but still extremely bad at it. This puts us in the position that we pretty much have to do it, because even while we’re terrible at it we still don’t have good stand-ins that can take our place. Having the machines help us along the way seems the most sensible way forward to me.

aseigo

aseigo

“Naaah,” I respond, digging into my own box of smelly opinions … :wink:

Haskell has great ideas but years and years of it being out there in the wild shows that it is more complex than is useful for nearly all developers working nearly all problems. This is not necessarily a failure, it is just a choice, and I do not think any amount of documentation will change the impact of those design decisions. Haskell is about the language, not the application of it. The designers of the language seem to understand this, fwiw, and are similarly ok with it.

I agree with the OP that Elixir (and, for that matter, for its day, Erlang) strikes a far more pragmatic road to walk down as a developer. That Elixir emerged with a few lighthouse frameworks (Phoenix, Nerves) from rather early on shows the application-not-the-language emphasis. This is also not entirely a good thing, but it does make it usually more practical to use.

Which is probably the biggest thing Haskell will end up giving to the world. Microsoft language designers pay a lot of attention to Haskell, it seems, for instance.

Probably just because Haskell is a poorer fit most of the time, and the rest of the time languages already in use for the other cases are acceptably not-bad-at-that-problem and so get selected even then.

I see a lot of non-web companies around here that are using “non-traditional” languages, but very few are using Haskell … even though the languages they choose are often either FP or draw heavily from FP ideas. shrug

LOL, yeah, I know that feeling … :slight_smile:

Where Next?

Popular in Discussions Top

Other popular topics Top

josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39247 209
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35953 110
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I'm a nov...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement