But other uses of monads, like say monadic parsers could be useful in other languages. And list comprehensions is also based on a monad in Haskell - this functionality is clearly useful in many other languages.
But without some kind of syntactic sugar (like do-notation in Haskell) the use of monads becomes far to cumbersome, and it ends up being easier to solve the same problem in an ad-hoc manner.
That's not true. It could still be useful to build up descriptions of IO that should be executed later, and an IO monad would be a fine way to do that in a language that provided the necessary capabilities to make that convenient.
Suppose we want a function that returns C = A + B, but only if A and B both exist. Otherwise C cannot be set with a meaningful value.
In an imperative language (python-esque?)I might do something like:
if A != NULL && B != NULL:
C = A + B
else:
C = NULL
in Scala: val C = for {
a <- A
b <- B
} yield a + b
What's the difference? In this example it is largely syntax, but let's do something with C. D = [1,2,3,4,5]
E = []
if C != NULL:
E = [x*C for x in D]
else:
E = D
So now we've got some complex logic. If C is set, then we want to multiply every element in D by C and assign the result to E.Without monads, I have to explicitly check for C == NULL before doing anything with it. The compiler isn't going to enforce that so it's possible I forgot to check and I segfault or NPE. Here's the monadic version:
val D = List(1,2,3,4,5)
val E = (for {
c <- C
x <- D
} yield c*x).getOrElse(D)
With an Option monad, I must use C inside the for comprehension. This is enforced by the compiler. If C is None, then cx won't execute and the for comprehension will return None. `getOrElse` on None just returns whatever was passed in, which in this case is D.So what did we gain? Again, it might just look like syntax. We swapped an `if C != NULL` and and `else` for a `c <- C` and a `getOrElse`. We actually gained some strong compiler guarantees.
Sort of a basic example and it might not be completely straightforward at first, but in my opinion once I understood how to effectively use monads (like Option and Try in Scala) my ability to simplify complex logic and be confident that it was correct increased.
EDIT: Haha... I botched my final scala example. That doesn't compile... something like:
val E = C.map{c => D.map(_*c)}.getOrElse(D)
would do the job.