Lack of easy piping is the shell-killer for me. Looks like Hell, similar to many alternative shells, require dancing with file handles and calling explicit methods on processes to set streams. It’s a shame because it’s the first alternative shell I’ve been curious to try recently.
Yeah I kind of agree with this. Ideally, it shouldn’t be that hard to do, especially in a language like Haskell where you can come up with nice operators for that.
It’s “very good” but nobody ever bothered to standardize it. We’ll see if MicroHs ever gets compatible concurrency, but it says a lot about GHC that it’s concurrency is enabled by a C-based RTS, and nobody has ever managed to fundamentally change much about it. For example, look at how many years it took to add the new WinIO runtime. Look at how GHC on WASM can’t take advantage of the WASM GC. Csaba’s external STG interpreter is another case study in how hard it is to achieve GHC compatibility.
That sounds very negative. But I don’t really understand why. I have had many great experiences with writing concurrent Haskell code, so far no negative ones. Is the problem that all those other Haskell compilers (… microhs and hugs I guess) will have trouble reimplementing GHC’s features? If so, that’s not specific to concurrency, but goes for quite a wide range of GHC features developed after ’98.
Yeah I think GHC being « the actual language » is problematic for other reasons — I remember a long time ago where I wanted to use JHC, and the compiler wasn’t implementing the right extensions I needed.
Also, note this is true for most modern languages (Go, Rust, Zig, etc. all have a reference implementation… and that only implementation). And I’m not sure why it would be a bad idea, especially when considering counter examples (D2 and dmd / gdc).
It’s good for the user, in comparison, I suppose. But it’s been there, like this, for 20 years or more now. I think it’s ok to move the goal posts, after all we have better tools like Rust now. Maybe it’s unfair to expect something like the JEP process, but it’s also important to be honest about it. I always see it repeated that GHC has amazing concurrency, so I think it’s fair to push back on that when it keeps getting repeated with no reference or comparison to the state of the art.
What exactly is it that you think should be better about GHC concurrency? You mentioned lack of standardization – which is relevant for compiler implementors – but is there anything you’re missing as a programmer about GHC concurrency? I ask because I really can’t imagine what it would be, but maybe that’s just my lack of imagination. I mean, there is stuff like Choreographic programming which provides further guarantees, but that’s something you get as a library, doesn’t seem like it required changes to Haskell.
My main issue isn’t with using GHC, my issue with what’s under the hood. There are papers about GHC, but they seem to describe an idealized version, and they’re not kept up to date when GHC changes. For example, I’ve seen it stated that the STG is neither tag-less nor a G-machine any more.
How would you add a concurrent runtime to MicroHs? I have no idea which text book to read. I’ve already written libuv bindings, but they don’t offer the green threading that GHC users have come to expect built into the runtime system. I think it’s interesting that all the dependent languages are missing a green threading RTS, though I think I’ve seen it stated that Lean plans to add one. Idris2 can use Rackets (which I rely on for my Idris2 HTTP libraries). I hope I will be able to understand the Lean runtime once they release it.
What? Where does this baseless claim come from? Every commercial Haskell project I worked on made very good use of Haskell’s concurrency features with great success. Concurrency is a breeze in Haskell, even for a beginner.
Yes, they do use STM sometimes, I’ve seen it used in commercial projects, but the only reason why STM doesn’t get used more is that Control.Concurrent.Async is much simpler and it addresses 99% of one’s concurrency needs, especially in combination with MVars, Chans, and my favorite: atomicModifyIORef'. The type signature of atomicModifyIORef' alone justifies why purely functional programming is a great idea:
atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b
It delivers the closest approximation to the dream of “concurrency for free”, particularly in combination with laziness, where a number of threads can transparently cooperate on updating complex data structures and evaluate only as much as they need.
Lack of easy piping is the shell-killer for me. Looks like Hell, similar to many alternative shells, require dancing with file handles and calling explicit methods on processes to set streams. It’s a shame because it’s the first alternative shell I’ve been curious to try recently.
Yeah I kind of agree with this. Ideally, it shouldn’t be that hard to do, especially in a language like Haskell where you can come up with nice operators for that.
It’s “very good” but nobody ever bothered to standardize it. We’ll see if MicroHs ever gets compatible concurrency, but it says a lot about GHC that it’s concurrency is enabled by a C-based RTS, and nobody has ever managed to fundamentally change much about it. For example, look at how many years it took to add the new WinIO runtime. Look at how GHC on WASM can’t take advantage of the WASM GC. Csaba’s external STG interpreter is another case study in how hard it is to achieve GHC compatibility.
That sounds very negative. But I don’t really understand why. I have had many great experiences with writing concurrent Haskell code, so far no negative ones. Is the problem that all those other Haskell compilers (… microhs and hugs I guess) will have trouble reimplementing GHC’s features? If so, that’s not specific to concurrency, but goes for quite a wide range of GHC features developed after ’98.
Yeah I think GHC being « the actual language » is problematic for other reasons — I remember a long time ago where I wanted to use JHC, and the compiler wasn’t implementing the right extensions I needed.
Also, note this is true for most modern languages (Go, Rust, Zig, etc. all have a reference implementation… and that only implementation). And I’m not sure why it would be a bad idea, especially when considering counter examples (D2 and dmd / gdc).
It’s good for the user, in comparison, I suppose. But it’s been there, like this, for 20 years or more now. I think it’s ok to move the goal posts, after all we have better tools like Rust now. Maybe it’s unfair to expect something like the JEP process, but it’s also important to be honest about it. I always see it repeated that GHC has amazing concurrency, so I think it’s fair to push back on that when it keeps getting repeated with no reference or comparison to the state of the art.
What exactly is it that you think should be better about GHC concurrency? You mentioned lack of standardization – which is relevant for compiler implementors – but is there anything you’re missing as a programmer about GHC concurrency? I ask because I really can’t imagine what it would be, but maybe that’s just my lack of imagination. I mean, there is stuff like Choreographic programming which provides further guarantees, but that’s something you get as a library, doesn’t seem like it required changes to Haskell.
My main issue isn’t with using GHC, my issue with what’s under the hood. There are papers about GHC, but they seem to describe an idealized version, and they’re not kept up to date when GHC changes. For example, I’ve seen it stated that the STG is neither tag-less nor a G-machine any more.
How would you add a concurrent runtime to MicroHs? I have no idea which text book to read. I’ve already written libuv bindings, but they don’t offer the green threading that GHC users have come to expect built into the runtime system. I think it’s interesting that all the dependent languages are missing a green threading RTS, though I think I’ve seen it stated that Lean plans to add one. Idris2 can use Rackets (which I rely on for my Idris2 HTTP libraries). I hope I will be able to understand the Lean runtime once they release it.
Also nobody bothers to use it. Because most people don’t understand concurrency, misuse it, or don’t realise they need it.
The people who really need it hand roll everything for huge performance boosts.
Concurrency is the most underloved, buggy part of software.
What? Where does this baseless claim come from? Every commercial Haskell project I worked on made very good use of Haskell’s concurrency features with great success. Concurrency is a breeze in Haskell, even for a beginner.
Do they use STM? Most developers have never even heard of it, and many Haskell developers only know if it and barely use it.
Yes I agree, concurrency in Haskell is fantastic. First class
Yes, they do use STM sometimes, I’ve seen it used in commercial projects, but the only reason why STM doesn’t get used more is that
Control.Concurrent.Asyncis much simpler and it addresses 99% of one’s concurrency needs, especially in combination withMVars,Chans, and my favorite:atomicModifyIORef'. The type signature ofatomicModifyIORef'alone justifies why purely functional programming is a great idea:It delivers the closest approximation to the dream of “concurrency for free”, particularly in combination with laziness, where a number of threads can transparently cooperate on updating complex data structures and evaluate only as much as they need.
Thank you. Thorough answer and edifying!