Monads are now of course seen by Haskellers as being very useful in many different use cases beyond the original motivation.
IO in PureScript, which I’d describe as strictly evaluated Haskell, is still implemented using monads. The biggest benefit of this (as one might expect) is forcing the separation of pure and impure code, but a cool byproduct is asynchronous IO is also implemented in a monad. Various functions are available to launch async from synchronous IO and lift synchronous functions into async. The ergonomics of mixing sync and async are better than any other language I’ve used.
So theres an interesting question: once you have dot syntax, are there reasons you’d still want lenses? I’ve come up with two.
First, it is nice to use “over” (%~) to avoid specifying a location in a data structure twice (first to read it and apply a function to the read value, second to create a new data structure with the read value replaced with the output of the function. The deeper the data structure, the bigger the benefit.
The second case is writing functions that take lenses as an input and operate generically with larger data structures without knowing where in the larger data structure the values of interest reside ahead of time.