Rambles around computer science
Diverting trains of thought, wasting precious time
Mon, 28 Feb 2011
Why I am not (yet) a functional programming enthusiast -- part 1
I suffer from a particular disposition which, for a programming languages researcher is quite an unfortunate one.
When I hear my fellow researchers expounding the virtues of functional programming, I start to feel grumbly. Functional programming is really
neat in a lot of ways. But there are some in which I find it unpalatable. Here is my first selection of complaints. They are mostly
to do with the generally poor comprehensibility of functional code. I have more complaints in reserve,
which will follow in due course when I'm feeling sufficiently grumpy.
- Short identifiers make for incomprehensible code. Functional code is often “concise” in part because
the prevalent style is to use ultra-short identifiers everywhere. This stands in stark contrast with Java, where a common style is
to make identifiers patronisingly verbose. The latter might make for swampy code, but the former is a great way of making code incomprehensible.
Even worse is the “primed” identifier idiom in Haskell. This is a nice way of saying “we have x,
and then we have x' which is somehow like x but somehow not like x, in a way that its name
completely fails to elucidate”.
- Currying is counterproductive. It's neat that we can specialise functions by partially applying them. But we can
do that with lambda expressions.
We don't need to turn all instances of multi-argument functional abstraction into the horrible multiply-indirect mess that is currying.
Currying is mathematically nice, but doesn't help the human programmer. The idea of a function from arguments to a result is fairly
easy to understand. The idea of a function from argument to function from argument to function from argument to result is not.
In fact, lambda expressions are a strictly better solution to
partial application, because we don't rely on arguments occurring in any particular order. By contrast,
if I have f x y z = ..., and I want to exploit the curried nature of this function
to do partial application, the first move has to specialise for x, and only then y, etc..
- Function application needs more signposts. Too much functional code consists of
an incomprehensible string of bracketless function applications,
with the occasional dot operator just to confuse things. Of course there's
nothing to stop you writing brackets, but, if you'll allow me to by cynical for a moment, since most of the satisfaction gained by functional programming
is gained from being “clever” (there's some famous wisdom about the dangers of that),
it seems that functional programmers rarely do this.
- Bogus analogies with mathematics, #1: advocates like to justify the “no brackets for function application” style
by analogy with the role of multiplication in algebra.
We don't write an operator symbol for multiplication because it's (arguably) the “common case”.
So, the analogy goes, we don't write anything for function application. This is nonsense.
The more significant reason we don't write a symbol for multiplication is that it's a cognitively simple operation:
for real numbers it is commutative, associative, and crucially,
operates within a closed domain. This means it is simple to reason about what it does,
so can be compressed notationally without making the result incomprehensible.
Function application has none of these properties: in general, it is not associative or commutative,
and relates values across distinct domains. Complex function compositions are already intrinsically hard to understand;
making them unreadable adds a ton of unnecessary incidental complexity on top.
Tellingly, note that in cases from mathematics where a multiplication operator does not
have the nice properties, such as matrix or vector algebra,
it is more common for mathematicians to write the operator explicitly, and to use more parentheses.
Perhaps they still don't use very many, but in any case,
as I'll argue in future rants, it's false (and groundless) to suppose that programming should emulate mathematics.
I concede that these are all elements of style, not language features per se. It's possible to write clean
functional code which doesn't suffer from any of the problems I've mentioned. This hints at the fact
that part of my problem is the culture among functional programmers, rather than the technology itself.
That's still a showstopper though, because in practice we are reliant on other programmers. Without other
programmers' having written tools and libraries that relieve us from writing everything from scratch, and documentation
to explain them to us, then no programming language is of practical use. Accordingly,
I'll be back later with a more concrete example
where this went wrong for me in an earlier foray into functional programming.
[/research]
permanent link
contact
validate this page