Until I found PureScript. Especially purescript-halogen [0], which is basically how one might make React in Haskell. Everything is still pure, but you can define nested state (not to be confused with React-style local mutable state!) without Elm's boilerplate wiring.
The "update" function runs in the continuation monad, which means that one can do something like this:
modify (\(State s) -> State $ s { loadingUsers = true })
users <- liftAff' $ fetchUsers
modify (\(State s) -> State $ s { users = users, loadingUsers = false })
and this runs asynchronously, but it still modifies one global state. Compare with Elm's "return fetch effect, fire event, react on event in update function".There's everything one might need in PureScript: functors, applicatives, monads, so the language feels much less constraining than Elm.
Drawbacks:
- they use bower for package management - it's ok, but elm-package's enforced semversioning is really nice.
- no default imports, so imports can get verbose [1]
- the error messages might not be as nice as Elm's, but I haven't had a problem so far, at all
- no elm-reactor - though since halogen is just a library, the UI is pure and there's no magic state-isolating runtime, you can probably roll your own relatively easily
- not as easy to pick up as Elm - but no problem for a Haskell programmer. Elm definitely focuses more on user-friendliness and Javascript converts.
...but these are minor nitpicks - I am in the process of making the switch and porting an app from Elm right now, and it definitely was the right decision.
[0] https://github.com/slamdata/purescript-halogen
[1] https://github.com/slamdata/purescript-halogen/blob/master/s...