> We're a Haskell shop (and have been for over 10 years now) and are finding agentic development with Haskell to work pretty damn well.
It not that it didn't work at all, so much as that it worked much better in other languages when we compared side-to-side. It's possible we had dev practices that could have been modified further to suit Haskell better (we had been doing that for years already), but increasingly I want the toolchain to adapt to us, not the other way around.
- None of us are experts in Rust, and we're all solid at Python.
- Rust felt like an under-correction for what we wanted (get all friction in front of the LLM out of the way).
- Our high-performance stuff is not being migrated at this time (Scarf Gateway), so we're just talking about basic CRUD backends here. Basically any language will work.
You might not like Microsoft but they did a video on why they re-wrote the last version of the Typescript compiler in Go. Basically, because of LLMs. It's worth viewing even if you don't decide to go with Go.
True that an interpreted language has a leg up on any compiled language in the arena of compile time, but worth noting that one of Go's primary design goals was improving compile times of massive code bases. Google was drowning under the weight of compiling huge C++ codebases and Go was the response to that (among other things).
Python is preferred because Python programmers are cheaper than other languages. Not because of any sort of technical advantages. Its literally the worse performing programming language in popular use. And it uses invisible characters in its syntax. Truly, it is the VHS of our industry.
Go compiles things at package-level granularity. You only need to recompile your reverse dependencies on making changes. Also there's build caching available out-of-the-box, as well as some support for test caching.
Using a frontier model you can combine it writing high-quality Rust and educate you in the process. You guys were too scared, needlessly.
But as others said: if Haskell was not giving you too much in terms of excellent typing system then maybe going for a PL with a much faster compiler like Golang would have been best for you.
I'd be very curious to hear your take if you gave another language a proper try for comparison with the same tools. I think you'll be as surprised as we were.
Hey, we have a 10 year old Haskell/Python/C++/TypeScript/Nix codebase, and use all of them regularly.
Haskell compiles slowly, but we have not found that to significantly inhibit AI-supported dev so far. We use ghci with `-fobject-code`, and our largest leaf module (10k lines of webserver request handlers) takes 8 seconds to `:reload`. To run stuff in it, the agent pipes `:reload`, or other invocations, into `ghci`.
Working on parts parts that are early in the module chain, such as our Prelude, makes the whole-project `:reload` take 50 seconds. Much of that could be avoided if we didn't suffer from the TH recompilation problem (https://gist.github.com/nh2/14e653bcbdc7f40042da3755539e554a). Originally I made a small GHC patch to hack that out (what this conservative recompilation protects from cannot happen in our project), which made the reload much faster, but the logic was changed in recent GHC so that doesn't work anymore.
In C++, we have some individual files (and thus compilation units) that take 45 seconds to compile.
Python is of course the fastest to (build+run). However, Python also has some problems with repeated runs: Once you have many imports, just starting the program (e.g. `--help`) takes ~2 seconds resolving imports. Do `import pytorch`, add another 2 seconds. For repeated runs, this can be a pain; Haskell and C++ are much faster for that, so they win when you don't have to change the code but repeatedly use already-compiled tools in a different way.
In all 3 languages, getting things to typecheck is very fast, because the agent directly reads the vscode LSP typechecking errors which are < 1s feedback. Claude Opus 4.6-4.8 understand all 3 languages very well.
I agree that GHC devs should focus most of their efforts on compile speed, and real-world pain solving. Some parts of that are indeed being done (e.g. newest GHC can write bytecode to disk to make the above workflow much faster, and codegen is by far the slowest part of compilation). But I think the focus should be even more on that. I consider most important and unsolved:
* solving Generics being slow to compile, especially for types with many constructors
* solving deriving classes being slow to compile
* solving TemplateHaskell causing too much recompilation
* doing staged compilation,
so that the next module can typecheck as soon as its imports are typechecked,
as opposed to waiting that codegen is done;
this unlocks a large amount of parallel work availability
All of these have open GHC tickets that I think should be the highest focus.
Other real-world production things are being solved quite nicely currently:
* The new Haskell debugger
* Much better stacktraces
* Much better runtime introspection to debug runtime hangs etc
I get your general point that if iteration speed (as in change code + run, 100s of times a day) is your highest value, Python does quite well. We intentionally chose Python for the part of the codebase that's relatively simple data importing but from 50 different sources, count growing adding new sources all the time, and need just quickly iterate on each until we got it.
But I find it would not be a great language for the other parts. Its concurrency story is bad, its interpreter is very slow and immediately disqualifies Python when you need to do e.g. a line of code for every 1000 Bytes (say for streaming small data chunks), typing is very useful but bolted-on and not always correct.
Things where Haskell remains best-in-class is anything nontrivial-webservers, I/O, program correctness, the main "general purpose" programming, refactoring and long-term maintainability.
LLMs removed some of the difficulty of Haskell, e.g. some interesting ideas to make things safer with sophisticated types or mechanisms like TemplateHaskell are now MUCH easier to implement in a few minutes. Also Haskell's general stance of breaking backwards compat in fundamental places if it's needed to make the language better, thus causing moderate amounds of upgrade grind, completely evaporated as a drawback because LLMs are extremely good at fixing type errors to bring code up to date with the latest changes.
The LLMs are very good at explaining Haskell compile errors.
Learning Haskell and maintaining projects in it is now easier than ever.
The number of compiler runs doesn't matter as much as the total elapsed time it takes to finish the task. In just about every test we ran, LLMs are faster at building in Python than Haskell.
Lisp/smalltalk programmers have been going on about this tradeoff for a long time. It mattered before LLMs too. Lisp/Clojure repl allowing you to compile tiny parts of your program inside your running program is incredible for your feedback/iteration loop.
Ironically, this is also what makes them shine with LLMs, the LLM has access to the running program and can modify it while it's running to get feedback instantly.
Complex type systems are cool. But, they are not free. I say this as someone who's first programming language was Haskell.
> I say this as someone who's first programming language was Haskell.
Amazing. How did that happen? Is it true that functional programming is only counterintuitive because almost everyone starts out with an imperative language?
> The number of compiler runs doesn't matter as much as the total elapsed time it takes to finish the task. In just about every test we ran, LLMs are faster at building in Python than Haskell.
How much faster? IOW, what's the difference (in minutes/seconds, not in percentages) between vibing Haskell and vibing Python?
Scarf Gateway is a core service of Scarf (https://scarf.sh) that we've been running in production since 2020. You can think of it as a powerful link shortener that can also sit in front of Docker containers, Python packages, tarballs, etc - any other artifact you distribute can sit behind it. It also emits logs that can be used for robust analytics that you probably aren't getting from your package registry provider today.
It was originally a nginx+lua service that we migrated to Haskell as the requirements became more complex. Now that the code has settled, we've open-sourced it, so you can self host Scarf Gateway or get involved with development!
Scarf | Director of Engineering | Remote (US timezones only)
Scarf builds builds maintainer-friendly tools for sustainable distribution of open-source software. Scarf identifies and connects open source projects with the companies that rely on their software.
If you love open source, love startups, and excel at leading great engineering teams, we'd love to hear from you.
Scarf | Director of Engineering | Remote (US timezones only)
Scarf builds builds maintainer-friendly tools for sustainable distribution of open-source software. Scarf identifies and connects open source projects with the companies that rely on their software.
If you love open source, love startups, and excel at leading great engineering teams, we'd love to hear from you.
It not that it didn't work at all, so much as that it worked much better in other languages when we compared side-to-side. It's possible we had dev practices that could have been modified further to suit Haskell better (we had been doing that for years already), but increasingly I want the toolchain to adapt to us, not the other way around.