|Think about Loose Coupling|
Re^4: Is it worth using Monads in Perl ? and what the Monads are ?by gaal (Parson)
|on Jun 14, 2007 at 06:24 UTC||Need Help??|
Rephrasing to mitigate the emotional stress: monads encapsulate effects. They aren't there to conceal in the sense of deception, but rather in the sense of information hiding.
I agree with the other poster who said the IO monad's the poorest one to look at, because I agree with you when you said a Perl program is in a(n IO) monad. But that's trivially true; the value comes when you look at the richness of different monads, and when you can take your code and separate functions out of it into those that really are pure and those that can be made to fit in monads a, b, c.
Here's a simple example.
This is part of the Pugs parser, the code to parse out the name of a sub. Inside the RuleParser monad, sequencing means "demand the following parse to work". But it also means take care of bookkeeping (source code position, name of what we're trying to do for use in error messages in case we fail). If a parse fails, the associated further bookkeeping is automatic. Here we say "first of all, look for a '*' string, but it's okay if we don't find it". The function string is monadic; if it failed then the function 'option ""' works much like a try/catch and provides the fallback. Anyway, now twigil is either "" or "*", and the position has advanced by 0 or 1 columns.
Now we try to parse a "name". We try a first parser, ruleOperatorName, and if it fails, ruleQualifiedIdentifier. If that one fails too, ruleSubName will fail. The actual behavior of that failure depends on who called us; if they were ready for us to fail (for example, by modifying us with "option" or "<|>") then a different parse might result higher up. Rewinding the position happens automatically, for example if we had already consumed a "*". But if not -- if we're in part of the Perl 6 grammar where the only conceivable term is a SubName and one could not be obtained -- then the user will get an error message saying Pugs was looking for a "subroutine name".
What I'm hoping I've shown is that all these bits of pieces of combining small monadic functions are common to the domain of parsing. Haskell isn't being deceptive in not making me put try/catch blocks over every line. It's encapsulating very specific and repetitive functionality.
I think one great difficulty in understanding monads is they take "if you look at it that way" to the extreme; and Haskell programmers often look at problems in surprising ways. Since parsing is a very practical problem, and familiar to Perl programmers at that, it's a good monad to learn with.