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.