Calling Purgatory from Heaven: Binding to Rust in Haskell
well-typed.com
well-typed.com
There was lots of discussion & debate around static vs dynamic, clojure vs haskell, oop vs fp, new languages vs established languages, conferences devoted to FP ideas, etc...
The whole debate ecosystem seems to have subsided around when rust really started taking mindshare. Now, I'm not implying here rust absolves these issues at all. It's just a co-occuring event on the timeline imho.
Although, I think it's probably obvious that devs who have free time use their attention on whats trendy. Rust probably took some wind out of the sails of haskell, but I'm not sure what trendy is moving to these days, maybe AI, but do devs really program against large AI models or just play around with chatgpt; if not, what are they interested in with regards to tools that materially affect their career?
What happened to all the debate about langs? What happened to interest (measured in frequency of online discussion) in FP? Is Rust still trendy in dev mindshare? Are these debates over/resolved?
I was writing Haskell in 2011. I'm writing Haskell now. I'll keep writing Haskell until I find something I like better. I also write C++, Python, R, and a dozen other languages when the mood or the need strikes. Some of my favorite bits of software are written in Delphi or poorly hacked together C. They're closer to rocks than Estwings, but they do the job (and have done since the '90s).
There will always be trends. There will always be floods. Floods can take you interesting places, but having a well-sheltered hole or a firm grip on something solid is probably the better long-term solution if survivability is the goal. In the end, COBOL devs are worth more than ever.
1. Web3 hired a lot of these people and so they had less time to work on this stuff. Shame to spend that much on a dead end but eh
2. Scala died with Big Data. It is still around and all but noone care anymore, which emptied the room. It also happened that the whole Implicits experiment for polymorphism, which scala was really supposed to explore, did not pan out that well
3. Effects progressed but... Mostly out of view. Ocaml shipped them with its multicore, we are seeing good work on the academic side, you see Verse wanting them, etc. Same thing with linear types.
4. Dependent types ... Never really crossed to the realm of production. And Idris and co are mostly "complete" so it slowed down
5. Oh and monad interest, mostly fueled by scala, died slowly. Effect handlers seems to be a nicer solution in practice to most of this stuff.
6. Typescript killed a lot of the need for advanced stuff, same with python and ruby shipping their stuff too. Meanwhile Rust and Elixir showed you did not need the really up there stuff to have results in prod.
In the end what happened is that a lot of the highly abstract stuff was driven by "hype domain" that died, while more pragmatic but limited implementation burgeoned and absorbed some of them. Rubber met the road and that tampered a lot of people down.
There is still work being done, but rn it is more at the "experimental language" stage. Think Rust in the mid 00s.
Oh and Rust mindshare is still growing. A lot. A looooot.
Both Rust and JS have adopted some FP concepts that are pretty nice, so there's that.
This is a recurring theme in my career. It's one of my cornerstone grievances with Nix as well (any time I need to write a Nix package I end up having to package some obscure C dependency that my package transitively depends on). :)
The AOLServer, which was heavily multithreaded and based on Tcl, was developed in 1995: https://en.wikipedia.org/wiki/AOLserver
You also can easily guess who of these two get i18n right earlier.
The AOLServer was made possible by the decisions to have an API to have specific versions of interpreters (including highly constrained safe ones), by forcing extensions to have per-interpreter state and make interpreters communicate by messaging on Tcl level. This resulted that if your extension worked with several interpreters in single thread execution, it would work with several threads ruunning in parallel. The same is for just Tcl code, which does not even know which thread it gets executed on.
Thus, Python developers did not do any looking around.
Later, a fully functional multiplatform binary package server/client was developed for Tcl [0]. It died of neglect while pythonistas spent (are spending) years trying to build something satisfactory.
I don't think this is a "sharp edge" (maybe "indeterminately long threads to pull") but it definitely is an unpleasant experience. If anyone knows of any good names for this category of frustration, I'd be happy to hear them!
Basically I suspect the majority of FP users liked the type system and general guarantees of FP but didn’t care about the ideological parts like purity or laziness so when a language popped up that gave you those guarantees but also had better UX and could bind easily to C or C++, they hopped on.
Also it’s much easier to sell Rust to management as C++ but with less bugs. Who doesn’t want less bugs?
All the demos I've seen of Idris suggest the compile time cost is substantial. So my best guess at present is the languages take too long to compile but that doesn't seem like it should be a deal breaker.
Because full dependent types imply no phase separation, as you say. Modern languages like Rust and Zig have introduced more powerful facilities for doing custom things at compile time, and perhaps dependent types can ultimately be viable in the compile-time-only subset of such languages; but we're a long way from dispensing with that phase separation altogether.
I work in Haskell full time now and have for more than a few years at this point. The ecosystem is small because there aren't any network effects propping up Haskell's popularity. We don't have large corporations like M$, Google, etc pouring dosh into GHC development, tooling, etc. It mainly survives on the community of dedicated folks working in academia, their spare time, and contributions from the small (growing!) pool of companies investing in it. Progress happens but it's slow.
This is one factor that can contribute to the cyclic nature of FP trends, Haskell specifically; a handful of influential people discover it, learn a bunch in their free time, write about it, and then when it fails to catch on they move on.
Another factor that contributes is... well network effects. Potential new programmers aren't rushing out to learn Haskell/OCaml/F# because there aren't a whole lot of jobs using it, there aren't a lot of courses teaching it, and there aren't many people recommending it. It also means that established language ecosystems are free to adopt ideas and features from the FP community in their own languages which further prevents people from leaving their ecosystem and adopting another language. Sure, C# may not be a great functional programming language but it's good enough and you don't have to fully buy in: you can use FP patterns when it feels appropriate and OOP ones when that works better (C# has the advantage of the .NET runtime which F# uses and the two can interop well... further preventing any reason to leave that space).
The set of Haskell programmers isn't empty. It's filled with people who are rather dedicated and passionate! And sometimes people new to Haskell join, learn something, and leave for various reasons. Some stay.
As for Rust well... if you look at just HN, again, I think you see these hype cycles. The early-mid 2010's the big trend was "X written in Go." Now it's, "X written in Rust." You don't see that happen much with OCaml/Haskell/F#... probably, again, because of the aforementioned effects. Either the pool of candidates re-writing existing tools is small enough that they can't break through the current hype-cycle or they're not re-writing those things and are carrying on with their work.
Every new fad is followed by folks that want to monetize conferences, books, training, consulting gigs,...
Eventually everything that mattered is said and done, a née generation comes along, and a new cycle starts.
Although i guess that makes C++ hell, which is appropriate.
I thought this might be a quote from the movie Trainspotting (1996). Seems to have a similar spirit to some of the things from that movie.
So many gems are C or system wrappers and require very specific versions of Ruby and whatever underlying libraries are called. That's fine on brand new dev projects, but it leads to a lot of unexpected web searches when it's time to ship code or return to a project you haven't touched in 6 months.
Pinning your gems helps with some of this but every time it popped up I thought ugh...here we go again. Eventually that pain made me look for a better way.
One of the oft-undersold features of Clojure is the culture is more careful with breaking changes.
The Rust philosophy is that there is nothing wrong with mutating state, as long as nobody can ever see you do it. :-)
Principled abstractions enabling unparalleled composition.
Usable effects libraries like effectful.
Easy concurrency and parallelism.
Fearless refactoring.
stm.
With that view it makes since to highlight either "Haskell v2", my ideal flavor of Haskell without reservation, or some mix of the two.
There's a time I wouldn't have mentioned effectul for exactly the reasons you allude to, but... I suppose I along with reasons cited, I no longer care that much in a way.
Doesn't lazy evaluation mean memory/complexity issues could manifest far away from the problematic code?
the reasoning is about correctness and program behavior
Haskell is still the only mainstream language that truly delivers on "understand the part without needing to consider the whole." Others can with work and discipline. With Haskell, you usually have to work hard to get in that level of quagmire (and I've seen and fixed plenty of quagmires. I've seen people complain about code too and just be wrong when I got my hands dirty for like an afternoon.)
I think the sibling response has a good answer FYI.
What would it do to make my life easier?
That's what makes it a hard sell I guess?
> What would it do to make my life easier?
It gives those advantages which I'll explain more in a moment everywhere, meaning you can depend on those things in your and others code.
Similar to how it's difficult to explain why it's insanely useful that emacs is plain text everywhere.
Now let's see if I can demonstrate how just one of these could make your life easier... Local reasoning.
A good definition:
> Local reasoning is a property of some code wherein the correctness of the code can be inferred locally under specified assumptions, without considering prior application state or all possible inputs.
Give me a second to think up a good example. Have a desired language or code example in mind that doesn't use local reasoning?
Most of the code I write needs to take in a chunk of floating point data a few thousand points long, do a lot of maths on it, and emit it back out again, as quickly as possible, over and over.
Beautifully done.
No, just based.
If this was calling Rust from Lisp, on the other hand…
Calling a C stub written in Rust using Lisp's C FFI is just your average Tuesday in comparison.
edit: and there are lots, already, where for each one it is difficult to tell where it lies on the spectrum from vapourware to production
Unless Rust has gotten runtime reflection without me hearing about it, I don't think writing the compiler in Rust gives you any special powers in interfacing with Rust. You'd get a lot more of a win from parsing the DWARF of a library when you dlopen() it, and using the type information that exposes to be able to use the full Rust ABI rather than the C ABI.
EDIT: Actually, no, even with runtime reflection, that would only help an interpreter, not a compiler.
That still wouldn't give you the ability to perform template instantiations at runtime though -- for that, you'd need to ship the Rust compiler with your Lisp _applications_, since you might be able to invoke a Rust template with arguments at runtime that hadn't been seen before.
If you're looking at work on building a more modern Lisp compiler, check out SICL or Clasp, though as far as I'm aware, those are both early-ish projects.