Recently, I found an article about a member of the Haskell Foundation – who was moving his company away from Haskell. The company built a hardware product with Haskell, and they were moving away reluctantly.
I’m not going to repeat the whole thing here (you can read it yourself, but the TL;DR; is: the Haskell compiler and tooling ecosystem was too slow, and that became a bottleneck now that the LLM agent writing the code is so fast.
Now, let’s be clear: I don’t want to start a holy war about “static versus dynamic typing”, so I’m not going to do that. I’m not going to discuss if the merits of static typing are overrated or not, and I’m not going to discuss if dynamic languages are more or less flexible. This was discussed over and over again – and nobody knows the result. And for me, that in-determination is also a result.
What I am going to talk about is the stubbornness of software developers. It’s something that’s been bothering me for a couple of years now, and it still bothers me today. Looking at this article was no different.
The bottleneck is the compiler
So, again, the big TL;DR; of the article: the Haskell tooling is too slow, and the agents are really fast to write code.
If an agent produces working code in, say, 20 seconds, and the Haskell compiler takes 5, 10, 15 minutes to compile… then the compiler becomes a huge bottleneck in the loop where the agent writes code, tests it, sees if it works, and rewrites it to iterate. The agent is done, and the Haskell compiler still didn’t finish.
And here’s the part that got my attention: the author moved from Haskell to Python.
This seems like a weird move to me, because they’re moving from a static language to a dynamic one. But the thing is – it also matches my own experience (I also started with some static typed language, and moved to Ruby/Clojure). And here’s the stubbornness part: this is something that people who like dynamic languages (like me) have been saying for literal years – He experienced something that we iterate, and explain, and prove, again and again and people are still fighting to believe us.
It’s not the LLM
So what’s different right now? It’s not the LLM.
Even supposing the LLM could write excellent code – or even good code (which, to be honest, has not been my experience – It’s mostly code that works, but that I would not write: full of defensive coding, and sometimes even duplications), the real difference between an LLM and a human is: a human programmer is usually proficient in 3, 4, 5 languages, and plenty of programmers are proficient in one or two at most.
The agent, on the other hand, is proficient in multiple languages, and it writes with the same code quality in all of them. Be it good or bad, it’s the same. And that is the interesting part – you now have a mythical “person” (a mythical robot, maybe) – that can produce, with the same ease and the same quality, code in both Haskell and Python: which means you can finally compare the two while holding the developer constant.
And what they found is that the number of defects in the Python code, over a given timeline, was the same as the number of defects in the Haskell code over that same timeline. (Probably fewer in Python, actually – otherwise why would they be moving away from Haskell? But I’m not going to guess). Uhnnn… who could have predicted, except the academic study that studied that in 2016, and that ANOTHER study in 2019 found the same conclusion?
What about quality?
So here’s what makes a good quality software: it’s the developer. And in this case, the machine is the same developer producing the same quality code in two languages. Which means they can measure how much the compiler was actually influencing the time it takes to write something – and what they found is that the compiler wasn’t helping them as much as you’d expect.
I am not going to be that guy and say that the compiler wasn’t helping at all – maybe it was – but the actual time to produce code of quality X was the same in both a compiled, static language like Haskell and a dynamic, interpreted one like Python.
And this, again, matches my experience.
The number of hours that I saw people spend producing correct, and quality code in C# and Java was the same – if not higher – than the time I saw people doing quality code in Ruby. Yes, sure: if you did a very bad Ruby implementation, it was very, very hard to read. But I also saw very, very hard to read C# and Java code. The type system helped me understand what the code was doing – but it did not help me write the fixed version because, for that, I usually had to change the type of some function… and changing that type would cascaded compilation errors over and over the codebase, forcing me either to write “adapter”, or “facades” or other techniques to fix the issue (again, structural typing might help but not by much – you can have the proliferation of very small, specific types that you need to merge and split, essentially making the whole thing a duck-typed code anyway)
Also, if I am writing new types, cascading it over the code, can I actually guarantee the same code quality? After all, am I not changing the shape of the data I’m sending, essentially invalidating the whole “this data have this structure and we’re sure of it”?
Dehumanization, again
You know what bothers me? I met people that worked in Haskell. Most of them would not accept, at all, any argument for a language with “weaker typing” (I wrote how that term is meaningless in the past, so I’m also using it in a meaningless way, just to be 100% sure) than Haskell – some would argue that we need more types and that it’s impossible to guarantee any quality in languages Clojure (because it’s dynamic) and even worse in Ruby or Python (because they are imperative). Few people actually wanted to listen to a different approach, to listen to the “Clojure guy” (usually that was me, before I quit most of the groups because they ended up discussing into theorems, category algebra, etc and less about software) about some different approach to solve a problem.
But… apparently, a machine is ok.
And the worst part? It’s the honeymoon phase. They are doing what LLMs are very good at – capturing a code that already exists, that have very well-define semantics, and porting that to another language. The LLM will probably be able to solve some issues on that migration, and probably will offer a good path for the future.
And that will be attributed to the machine – not the humans that wrote the first Haskell code, well-written, in the first place.
Exactly like they listened to the machine saying that “A dynamic language can produce code faster, and we can iterate sooner on that result” than us, developers of said language saying the exact same thing over the years.