I haven't done much Haskell programming, but this feels a little dirty to me. Can other Haskell coders chime in and tell me if this is good practice? It does seem cool to have functions return different values depending on what you ask for, but especially as a parser it seems like it would be fragile.
This technique is quite common for generic conversion from some low level serialization (like XML, JSON, binary, etc) to more high-level typed Haskell values. And this is certainly considered to be good practice.
The true value comes from the fact that it only works, as explained in the article, when the type of the return value is known. This makes it very hard to make mistakes.
I use this form of value based polymorphism a lot in practice and wouldn't consider it fragile. Especially in combination with generic programming it allows you to write (or even derive) very concise conversion functions that are very safe in use.
There's not really a line between parameters and values in Haskell. Static values can just be thought of as constant, zero-arity functions. The heart of this is, to me, more generally thought of as polymorphism on the return type.
Read is a great example of this working very well. It's, as you say, not really robust enough to work at the API or program level, but Show/Read provides a pretty quick, everywhere available serialization for many values. It's vital for debugging at the REPL.
Probably the most notorious example is the newbie-killer Regex library which uses polymorphic return types to dispatch what kind of result you want from your match, such as the match index or a list of group matches. It seems really clever since you just call the match function and affect whatever kind of pattern matching you want in order to pull values out, but it has always smelled to me since it's very hard to discover the functionality — the polymorphic return types aren't opaque, but are burdensome — and seems quite a bit too magical.
So I wouldn't personally go wild with return type polymorphism. It's obviously necessary in order to write things like filter, but unless the return type is simple and easily inferred by both compilers and people it can get hairy fast.
Thinking of values as functions is more misleading than it is illuminating. There are values that are functions, and there are values that are not, and the type system is extremely clear about which are which. It's just that all values can be polymorphic, including functions.
On the contrary, this is both very common and is considered good practice where appropriate. Haskell's strong static typing and compilers will make sure there is never any ambiguity as to which instance is used. Everything has to tightly fit together or else your program won't compile.
Well, yes, you wouldn't want to base a whole parser around this feature of the language. He was just saying that it gives read and show enough power to act like a simple parser. For full-fledged parsers in Haskell, you'd generally want to use Parsec, which is much more complicated and appears at first to be built entirely out of funny-looking combinatorial operators.
There also seems to be a fair amount of momentum around attoparsec, which has fewer features than Parsec but is very fast and works on bytestrings. Either is good; parsing is one area where Haskell really excels.