Actually the most important part of monads in Haskell is the do-notation. Without that, monadic code would look like JS' callback hell (although composition of monads using monad transformers/monad stacks isn't much better).
I still think that it would look a lot less bad than JS callback hell, mostly because of syntax.
actA >>= \a ->
actB a >>= \b ->
pure doSomethingWith b
is a lot better (to my eyes) than:
actA(a =>
actB(a, b =>
doSomethingWith(b)
)
)
and it gets worse from there (blocks to have statements to declare variables, or to call multiple functions. pre ES6 those would've also been functions rather than lambdas. Admittedly monad transformers aren't that great, but that's mostly because of the nxm amount of instances (to avoid explicit lifting).
Disclaimer: personal opinion
Having used both extensively over the years... I'll have to disagree. Don't get me wrong, purescript is awesome in its own way, but it falls short of haskell in a few major ways.
- Lacks ergonomics (for example it has better extensible records, but they are clunky to manipulate due to the lack of features at the type level)
- as of now it's tied mostly to the JS ecosystem and runtime(s): that means no TCO, which _really_ hurts when using monads that require on a lot of recursion. And in fact purescript sometimes has to take a performance penalty and use specific trampolined stack-safe monads to avoid stack overflows
- Haskell layout rules may be complex, but purescript's break in weird and unintuitive ways (by layout rules I mean the indentation-sensitive syntax)
- Haskell is catching up on _a lot_ of the feature that made/make purescript great (mostly talking about syntactic things right now, like RecordDotSyntax, QualifiedDo, BlockArguments...)
- as it turns out, when programming "Haskell-style", laziness is really damn effective. So many times I've had to forcefully (and painfully) introduce laziness in purescript to make things behave well...
As much as I like purescript, I think if you want that kind of strict programming, maybe OCaML or a derivative thereof (or maybe even ReasonML/Rescript?) would work better? I feel like whenever I use purescript it looks so similar to Haskell that I try doing things the haskell way and it just doesn't work, and the "purescript" way will often look weird to a trained haskeller.
Yes, it does do some things better than Haskell. And row types and row polymorphism are a really nice way of handling records and some type level programming.
Haskell without laziness is Purescript, btw.