|
![](/i/fill.gif) |
You remember the 80 / 20 rule, right?
No, not the rule that 80% of the population falls within 2 standard
deviations of the mean; that one's actually baloney. It's only true *if*
the data follows a normal distribution - which is by no means always
true. And even then, it's 95.449%, not 80%. :-P
I'm talking about the rule that says that 80% of people only use 20% of
the available functionality. Or that 20% of the development effort
implements 80% of the functionality, and the last 80% of developer time
is required to do that last 20% of functionality.
So I'm writing a Haskell parser. The vast majority of Haskell code uses
very simple syntax. But it seems the language specification includes a
huge amount of flexibility that hardly anybody uses. Today I've
discovered things I didn't even know you could *do*!
For example, one way to do pattern matching in Haskell is with a case-block:
case list of
[x] -> x
[x, y] -> x + y
[x, y, z] -> x + y + z
_ -> 0
This takes a list and adds its elements, unless there's more than three
of them, in which case it returns 0. Simple enough, right? Well, you can
also add "guards" to a pattern:
case list of
[x, y, z]
| x < 0 -> ...
| x > 0 -> ...
| x == 0 -> ...
Well, it turns out you can have *multiple guards* on a single expression!
case list of
[x, y, z] | x > 0, y > 0, z > 0 -> ...
What does that even *do*?! <read the spec/> OK, so it seems it's the
logical-AND of all the conditions? So, um, why not just write it as an AND?
But it's worse. Apparently you can write local declarations *inside* a
guard. And the variables thus declared are in-scope for the rest of the
line. Wuh?!
case list of
[x, y, z] | let w = x + y + z -> w
WHY WOULD YOU DO THIS?!
But wait, it's worse: you can put a pattern *inside* a pattern guard...
case list of
[x, y, z] | [a, b, c] <- x, [d, e, f] <- y, [g, h, i] <- z -> ...
This mind-bending snippet does precisely the same thing as
case list of
[[a, b, c], [d, e, f], [g, h, i]] -> ...
Except that the latter is actually *readable*. (It matches a 3-element
list of 3-element lists.)
The only reason I can think of for this obscure feature is to allow
somebody to do something like
case mode of
ModeX info | let sub = decrypt info, SubmodeXK <- sub -> ...
In other words, pattern match, run a function on the result, and pattern
match again on the result of that. But, seriously, WHAT ARE YOU DOING
WITH YOUR LIFE?! That is *way* too much crazy to try to squeeze into one
equation. For the love of God, break that stuff into something smaller!
case mode of
ModeX info ->
case decrypt info of
SubmodeXK -> ...
There. That wasn't so hard, was it? :-P
Also slightly nauseating is that you're allowed to specify operator
fixity declarations inside a local variable block. But I guess that's
not really so bad; I suppose the *bad* thing is that you're allowed to
declare local operators in the first place!
let
x # y = x * cos y
infixl 7 #
in 1 # 2 # 3
This declares a new "#" operator, which exists only inside this one code
block, and has a precedence of 7 and is left-associative. If you were a
really sick human being with serious mental problems, you could create a
loop where an operator does something different on each pass through the
loop.
Oh God, wait... You can do all of this *inside* a pattern guard!
case list of
[a, b, c] | let {x # y = x * cos y, infixl 7 #}, a # b # c > 0 -> 1
MY EYES!!! >_<
Post a reply to this message
|
![](/i/fill.gif) |