- Monads with do-notation
- Atoms
- Immutable data structures
- Monads with do-notation
- Atoms
- Immutable data structures
Phrased like this, it sounds like 'the monad abstraction' and 'good syntax for monads' are what helps, which is slightly off the mark.
But particular monads do help:
- The Par monad gives you deterministic parallelism for computations.
- The flipside of marking mutable/non-determistic functions as IO (another monad), is that the functions not marked as such are deterministic, non-interfering etc., so interleaving them differently will not grow the state-space.
- The STM monad gives you transactions, which give you safe, shared mutability without running into the following issue from the article:
> I can use programming constructs like mutexes and barriers to "prune" the state space and give me the behaviors I want, but given how big the state space can be, I have to do a lot of pruning to get the right behaviors. I can make mistakes in implementation, "misshape" the space (like by adding a deadlock), or not notice a buggy state I need to remove. Threads are very error prone.
I'm not sure what 'Atoms' refer to, unless it's running code in an atomic block in STM.
That said, having a good monadic syntax is still great, even if the syntax can't solve semantic concurrency issues. I believe that CompletableFutures were a good way to model async code in Java (and Rx/observables etc, to some extent). But they got resistance from Java programmers who didn't want to flatMap everything all the time. They had semantic issues too (can't cancel?!? what?!). But I think it's largely their syntax that made programmers miss the Thread model of writing straight-line imperative code.
You'll also come across them in Lisp-like languages and logic programming.
Edit: Another, maybe better, illustration from the BEAM might be the 'booleans', they're implemented as the atoms :true and :false.
> But particular monads do help:
The part the language needs to provide are merely the abstraction and the good syntax which uses it, not the particular monads: you can then implement them as required.