|P is for Practical
Re^4: Is it worth using Monads in Perl ? and what the Monads are ?by BrowserUk (Patriarch)
|on Jun 27, 2007 at 04:00 UTC
S'funny thing, but since writing that, I just came across the smart and very helpful tmoertel's Type-based solution to the strings problem. It's a very interesting piece and a powerful argument in favour of strong, static typing. Almost...
Right up until the last section where he says:
To be clear, the fundamental problem of having to manage different kinds of strings is still with us. As programmers, we still must understand the differences between URLs, XML, SQL, untrusted user input, and so on. But now, we don’t have to be perfect. As long as we can reliably slap the right type on a string when it first appears, we can let the computer worry about it from then on....
At which point I though: You know, it isn't hard construct a few types in Perl.
Of course, with this implementation the programmer can easily bypass the wrapping and grab the contents directly. But, if he does, he's taking responsibility for his actions. Also, there are other forms of OO, like Object::InsideOut that can be used that will prevent casual breaking of encapsulation.
The real difference of course is that there is nothing to prevent the programmer from calling the wrong method and sticking the TextPlain representation of a url where the HTML representation should have been used. There is no compile-time checking of what methods are called on an object, or in what context those methods are called.
The runtime errors will catch attempts to call non-existent methods. But they won't catch the use of existing methods in the wrong context. Interpolating a URL as plainText into a string of HTML for example. However, Dominus' Interpolation could be used to go some way to achieving that. It still relies on runtime though.
The real trick with Haskell is the Monad. It won't let us take the special strings out of their wrappers and so mix them up with other 'normal' strings. Any (unwitting) attempt to do so is caught at compile time. It does of course allow us to liftM functions designed to operate on normal strings so that they can be used on the special strings, within their wrappers, without needing to take them out. Though we might need to use liftM2 or liftM3. (Is there a liftM4).
As these strings are [Char] (list of char), then we might want to use some of the many list manipulation functions upon these 'special' lists of char. So we need to use mapM rather than map, and concatM instead of concat. Or maybe we need one of fold1 or foldr, or preferably (in most situations it seems) foldl'. Hm. Seems there is only foldM which is really foldl under the covers, with all the unpleasant implications for stack usage that has. Gettin' messy in'it.
You're right. You can extract data from a monad. Here's a typical comment about doing so:
Strafunski defines an instance for IO as instance MonadRun (->) IO where run alg = alg . unsafePerformIO, but since users aren't generally supposed to call unsafePerformIO, I don't think this is a good idea.
So, you wrap stuff (like unsafe user input), in a monad and reap all the benefits of compile-time type safety, but with the caveat of all the awkwardness and special treatments (special functions) that entails.
Or, you unwrap them using a run"monad" function (Functor?), and forgo the benefits of having put them there in the first place?
I guess that you could write the runTaint er ... thing, so that it took a regex and validated the string against some criteria before passing you back an untainted [Char]. Sounds familiar. But...
With type signatures like ( RegexLike a b => RegexContext a b (b, b, b, [b]) ) and RegexLike a b => RegexContext a b [(MatchOffset, MatchLength)], lifting those into a taint monad is scary. And of course, we'll want to wrap those inside a Maybe monad so that we can deal with failures nicely. Even scarier.
But the real problem is that I don't see any substitution operator? Maybe I missed it. In Perl, we can untaint things by stripping away anything that doesn't match what we need and extract what's left. Sure we can pattern match against all the possibilities and manipulate the (wrapped) string to produce what we want, but that gets incredibly tedious and costly.
The point is that it's a free world, and the language provides you with the tools to build this stuff on your own. No one has to implement taint mode for you.
Another way of saying that is: You have to implement taint mode yourself!
Yes, I have no doubts that it is possible. I wouldn't want to be the one trying to do it, but there are some smart guys out there will do it for us eventually.
But that's what puts the Practical in Perl. It may not allow the programmer to easily implement all this stuff themselves, but it doesn't need to. Pretty much everything you need is right there out-of-the-box, and has been for years. Making the hard stuff easy--and giving it to us in nicely integrated, usable forms out of the box--is exactly the benefits you get from Perl.
Don't get me wrong. Haskell is amazing. The strong static typing and monads and its ability to add to the syntax are immensely powerful and allow the expert Haskell programmer to achieve pretty much anything. But it does require a huge learning curve, deep technical understanding, a huge compiler, complex libraries that are catching up with Perl in some areas (like regexes; having far exceeded it in others for a long time).
But Perl has been doing the business for thousands of people for years and years and without requiring them to have MSc's in Computer Science. Sure, it showing it's age and there are things on most Perl hackers wouldn't-it-be-nice-ifs lists, that it can't quite deliver through cpan or XS.
But then Perl 6 is 'just around the corner'. It's been a long straight road approaching that corner, and perspective is deceptive. The corner may still be further away than it appears, but for good reasons. And once again, that same pragmatic, Practical approach to language design will prevail.
The most useful, most used, most bang-for-buck features other modern languages have, will have been incorporated into the base syntax in a concise, compatible, usable way.
Apply as much of the 'withouts'--B&D, objects, FP, purity, laziness, readability, reflectivity, et al-- as you need, without having to apply it to everything you do, or give up all the others, to achieve it.
My personal beef with Haskell is not what it can do, it's what it makes me give up in order to be able to do it.
It's all about trade offs, and Mr.Wall has, for me, an uncanny knack of whittling away the powerful arguments, hype and doctrine underlying the zealous fervour of each of these schools of thought and extracting the bits that the majority can benefit from, without their needing to convert on-masse to use them.
I'm not sure if you are the same anonymonk as wrote Re^10: Is it worth using Monads in Perl ? and what the Monads are ?--from the tone, probably not--but the Q language referenced in that post shows that Functional Programming doesn't have to be 'pure'. Indeed, it can be very 'practical', and can even gain power from being so. (Runtime symbolic expression manipulation with having to add another level of parser.)
My point is, every language makes fundamental choices about it's design. In the context of Haskell's strong, static type system, monads are a powerful, useful feature that allow (some would say, 'are required' for) it to do some very clever things.
In the context of Perl, monads would be an obscure, manual, tedious drain upon resources that dynamic (semi-compiled) languages can ill-afford, and that would produce few benefits for considerable costs.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.