Another reason monads are cumbersome in other languages is that other languages use lazy evaluation. If you consider the naively implemented function
skipMany :: Parser a -> Parser ()
skipMany p = (p >> skipMany p) <|> return ()
and then consider how you might write it in some other language, you'll note that the translation, strictly evaluated, gives infinite recursion. To practically work with monadic computation requires some form of non-strict evaluation. Another, less catastrophic example would be the following.
printNTimes :: Int -> String -> IO ()
printNTimes 0 s = return ()
printNTimes n s = putStrLn s >> printNTimes (n - 1) s
Strictly evaluated, that would build up Theta(n) memory usage.
For this reason, the more computation-oriented monads cannot be used practically in other languages without added weight to avoid strict evaluation.
Ironically, it's the non-monadic uses that cause the problems -- those that don't need the full power of 'bind', i.e. uses where the monad's user doesn't pass return values from previous actions to future actions. When you pass a return value, you end up needing a lambda expression, which cuts off strict evaluation. When you only use them in ways that applicative functors can be used (which often applies for parsers), that's when you suffer. It's not the end of the world; there certainly are workarounds, but that requires adding explicit promises everywhere, which is just a pain.
The first example, naively translated to scheme, results in:
(define (skip-many a)
(or (and (a) (skip-many a))
(void)))
This is not infinite recursion. The Parser monad used in the Haskell version is simply a stream dressed in monadic clothes (and even C has streams a-la FILE*).
As for the second example, the naive translation to scheme is:
Neither of your translations convert your code to anything that has to do with monads, and your first translation is just plain broken.
Your print-n-times doesn't return an action---it's an imperative function that performs an action.
The naive translations to Scheme would be as follows:
(define (skip-many p)
(<|> (>> p (skip-many p))
(return 'nothing)))
(define (print-n-times n s)
(if (= 0 n)
(return 'nothing)
(>> (put-str-ln s)
(print-n-times (- n 1) s))))
In order to fix the infinite recursion in my first example, the parsing framework I made in Scheme had a macro `thunk-parser` (actually, it had a shorter, stupid-sounding name) which for all intents and purposes just wraps the expression in a (lambda ()).
Agreed; neither of the translations use monads, because monads are a semantic hand-job proscribing order within a declarative language. However, Scheme is not a declarative language, therefore order is implied in the structure, therefore monads aren't necessary.
>> Your print-n-times doesn't return an action...
Nope, look again. It returns the results of applying `void'. Who knows what (void) may return in a loosely-typed language?
>> ...it's an imperative function that performs an action.
Well, considering Scheme is an imperative language with side-effects, it's hard to dodge such criticism.
>> The naive translations to Scheme would be as follows...
That's not a translation from Haskell to Scheme, that's writing Haskell using a prefix syntax.
>> Also, both your examples rely heavily on non-strict evaluation. 'and' and 'or' are both macros that non-strictly evaluate expressions.
I went back and re-read your original post:
>> ...you'll note that the translation, strictly evaluated, gives infinite recursion.
Mea culpa--I completely missed your point that translating from a turing complete language to a non-turing complete language might have some pitfalls.
Then maybe I'm misunderstanding the point of your reply. I was pointing out how monads are inconvenient to use in strictly evaluated languages. Why did you follow up with an example about how not using monads is convenient?
>> Then maybe I'm misunderstanding the point of your reply.
I was pointing out that your examples don't make sense, as it's trivial to
translate the Haskell code into another general purpose language (such as
Scheme, C, Perl, Fortran, etc), while impossible to translate into an eager (strictly evaluated) language (such as...?).
Additionally, the reason monads are cumbersome in other languages has
nothing to do with eager/lazy evaluation, or conditional computation, and
everything to do with the fact that monads exist in Haskell to solve it's
sequencing problem (arising from the fact that it's a declarative language).
Imperative languages have no problem with sequencing, and therefore have no
need for monads.
The bottom line is that monads are not practical without some kind of syntactic sugar like do-notation. Without that, you have to write operations as a chain of nested lambdas, which becomes very ugly very quickly.
This is probably why monads haven't taken off in any language beside Haskell.
For this reason, the more computation-oriented monads cannot be used practically in other languages without added weight to avoid strict evaluation.
Ironically, it's the non-monadic uses that cause the problems -- those that don't need the full power of 'bind', i.e. uses where the monad's user doesn't pass return values from previous actions to future actions. When you pass a return value, you end up needing a lambda expression, which cuts off strict evaluation. When you only use them in ways that applicative functors can be used (which often applies for parsers), that's when you suffer. It's not the end of the world; there certainly are workarounds, but that requires adding explicit promises everywhere, which is just a pain.