Function progamming is all the rage. Teedy Deigh considers how it offers many opportunities for the serious programmer.
Functional programming has, of late, taken its flight path across the radar of the industry, awaking from its paradigmatic slumber to threaten the livelihoods and codebases of hordes of OO half adopters and procedural laggards. How far should it be followed to keep one’s job and reputation secure? What opportunities does it offer for programmer idiosyncrasy and awkwardness? This is clearly a matter that warrants further study.
As with any serious research effort, the dictionary is our first stop. It offers the following possibilities:
functional , adjective
- having a function
- working or operating
- useful, utilitarian
- designed to be practical rather than attractive.
For the paid programmer this sends out a mixed message. The first point is certainly met by much code. Indeed, there is an implication that one function is sufficient, thus cramming it all into
main
should be enough to meet this requirement. The outlook is good for many programmers who rely on such extreme encapsulation techniques as a means to differentiate their code from so-called clean code. But the second definition is not so welcoming for anyone whose expertise and day-to-day practices and heroism find expression in bugs and the debugger. Similarly, the joy of much programming is in considering it an art rather than some demeaning utilitarian endeavour, where
stakeholder value
is the only dull reward. The last definition offers mixed possibilities: that the code need not be aesthetically pleasing can be considered a good thing; being practical misses the point of much coding effort and advice. For example, a large part of the investment in OO is based on the premise of reuse rather than use, which is the perfect get-out for anything that may be criticised as not at first appearing useful.
There is a certain air of elitism that surrounds functional programming, which for some programmers allows them to retain a mystique and priest-like status. This is to be applauded, especially if the code is similarly shrouded in mystery. Yet at the same time there is something more hoi polloi about functional programming that threatens to wrest programming from the grasp of the few and deliver into the hands of the many:
Excel is the world’s most popular functional language.
~ Simon Peyton Jones
It is important to remember that for a programmer:
The needs of the one outweigh the needs of the many.
~ James Tiberius Kirk
Thus some kind of distance from the common world of Excel, any kind of secret knowledge or obscure technique that can be brought into play, is needed if functional programming is to be taken seriously by real programmers.
Fortunately, the close association between mathematics and functional programming looks set to provide such separation. For those less comfortable with mathematics, but who revel and dwell in the darker corners of procedural coding, there is also hope:
Haskell is, first and foremost, a functional
language. Nevertheless, I think that it is also the
world’s most beautiful imperative language.
~ Simon Peyton Jones
While beauty may not be a selling point – the very word functional suggests this is not a credible consideration – the imperative opportunity is in the imperative support:
The determined Real Programmer can write FORTRAN programs in any language.
~ Ed Post
Given that functional programming can be coaxed into something more familiar, it makes sense to probe a little further. And how better to understand FP than to appreciate the problems for which it is ideally suited? For example, OO programmers are drawn to bank accounts and stacks, enterprise architectures meet the needs of pet stores everywhere and TDD satisfies a collective need to understand Roman numerals and the rules of ten pin bowling. What then is the killer app for functional programming? There are many, but one that deserves our special attention is the factorial function – a pressing need for which seems to exist in teaching texts everywhere.
Where a modern C programmer might be satisfied with the following, with its exemplary use of postfix decrement, discreet use of the ternary operator and nod to design by contract (along with the “To
NDEBUG
or not to
NDEBUG
?” question it leaves in its wake):
int factorial(int n) { assert(n >= 0); int result = n ? n : 1; while(n-- > 1) result *= n; return result; }
The true functional programmer understands that:
To iterate is human, to recurse divine.
~ L Peter Deutsch
which gives us:
int factorial(int n) { assert(n >= 0); if(n == 0) return 1; else return n * factorial(n - 1); }
To achieve full divinity, however, requires the following:
int factorial(int n) { assert(n >= 0); return n == 0 ? 1 : n * factorial(n - 1); }
Enough to make many newbie programmers and maintainers mutter “God” under their breath. Their awe mingled with a lack of appreciation of the qualities the conditional operator can bring to a codebase when employed extensively and without mercy. It is worth noting that conditional expressions are the norm in functional programming, although they often lack the brevity of C’s ternary operator.
That said, however, it is considered good functional style to express programs as transformations expressed through other functions, often those found in a standard library. While any good programmer makes some use of libraries, there is always a balance to be struck, always a sense that it is the programmer who should be writing the reusable code rather than actually reusing it.
The following version of factorial is implemented in Haskell, a pure functional language whose name is the outcome of a word association game where the chain of connections took in one of the fundamental programmer food types and the logician Haskell Curry:
fact n = product [1..n]
The definition of the
fact
function is brief and clear, with clarity being perhaps the major objection to adopting this approach in legacy-wannabe code. That said, the brevity of identifiers popular in functional programming is a welcome relief to anyone whose fingers have laboured over the enterprisey
FactorialCalculationFunction
(with a further liberal assortment of
Manager
,
Controller
, etc. suffixes waiting in line for inclusion), but at the same time offers sufficient scope for challenge and humour. Instead of the painfully obvious
factorial
, programmers can choose from:
-
the boldly assertive
fact
; -
the chatty
fac
; -
the wry
faq
– factorial is, after all one of the most frequently asked-for programming examples; -
the vowel-deprived
fct
– a puzzle for its readers to solve or an opportunity for vowel-injected humour; -
the enigmatic discretion of
f
.
It is worth learning the lessons and orthodoxy of the Haskell version, while keeping in mind the following:
The code is more what you’d call
guidelines than actual rules.
~ Captain Hector Barbossa
Thus, the optimal solution for factorial is one that combines considered naming with artisan-crafted logic.
Turning to larger programming problems, one of the major challenges – and therefore one of the major opportunities for programmers to inject themselves into projects as dependencies – is the question of state change.
In general, functional programming shies away from state change. It is easy to see that if state change is ignored, code achieves many non-functional qualities – interactions with databases don’t function, user interaction doesn’t function, etc. Indeed, any I/O or interaction with the physical world become completely non-functional. Sadly, for all the purity that this offers and peace that it brings – databases and users being a prime source of annoyance and bugs – a complete lack of state change is likely to attract few sponsors. To get around this, functional programming languages generally adopt one of three approaches – pragmatism, actors or monads:
- Pragmatism is often another way of saying, “We know this could be better, but that looks a bit tricky and, quite frankly, we can’t be bothered.” When used as a prefix, pragmatic is often shorthand for not , as illustrated by, for example, pragmatic Agile, pragmatic TDD, pragmatic OOP. Thus the question of functional I/O can addressed with pragmatic side-effect-free code.
- The actor model of computation is based on role playing and pretence. Instead of actually doing the I/O yourself, you employ an actor to do it for you. Actors pretend they’re not doing anything – as the name suggests, it’s all an act – but they’re really doing I/O, and probably quite a lot of it. In common with their high-profile real-world namesakes, if you ask actors if they’re doing anything questionable they’ll deny it, which spawns a whole network of gossip (i.e., messages passed discreetly from actor to agent to journalist).
- It is perhaps fitting that monad rhymes with gonad, reflecting the common response to the masterful way in which I/O with monads is passed off as being free of side-effects by burying it so deeply in category theory – wrapped in a mystery inside an enigma spliced in a riddle encrypted with AES – that it becomes almost impossible to determine whether there is any I/O. Simply trying to work out what we mean by ‘I/O’ and what we mean by ‘what we mean by’ is usually enough to distract practitioners and theoreticians alike from any I/O that may (or may not) be happening, while also noting that maybe is itself a monad.
Thus, functional languages largely manage to achieve state change through a process of full-scale regime change.
As in other walks of programming, FP is unsettled on certain key issues, such as whether to favour dynamic typing or static typing, so the programmer can feel right at home and just as entrenched. Matters of syntax also offer scope for heated and vibrant discussion, with handwaving use of elegance often used to sweep under the carpet the frequent similarity between functional programs and /etc/termcap files. Hybrid languages provide a certain postmodernism relief to the clean lines of much neoclassical or modernist functional programming.
Although the claims of clarity, brevity and purity are enough to put many programmers off, we can see now that functional programming offers many opportunities for the serious programmer.