After spending a lot of time reading and thinking, I think I have finally grasped what monads are, how they work, and what they\'re useful for. My main goal was to figure ou
As always, the IO monad is special and difficult to reason about. It's well known in the Haskell community that while IO is useful, it does not share many of the benefits other monads do. It's use is, as you've remarked, motivated greatly by its privileges position instead of it being a good modeling tool.
With that, I'd say it's not so useful in C# or, really, any language that isn't trying to completely contain side effects with type annotations.
But it's just one monad. As you've mentioned, Failure shows up in LINQ, but more sophisticated monads are useful even in a side-effecting language.
For instance, even with arbitrary global and local state environments, the state monad will indicate both the beginning and end of a regime of actions which work on some privileged kind of state. You don't get the side-effect elimination guarantees Haskell enjoys, but you still get good documentation.
To go further, introducing something like a Parser monad is a favorite example of mine. Having that monad, even in C#, is a great way to localize things like non-deterministic, backtracking failure performed while consuming a string. You can obviously do that with particular kinds of mutability, but Monads express that a particular expression performs a useful action in that effectful regime without regard to any global state you might also be involving.
So, I'd say yes, they're useful in any typed language. But IO as Haskell does it? Maybe not so much.