The Rise and Fall and Rise of Functional Programming (Composing Software)
<< Start over at Part 1 | Next >
When I was about 6 years old, I spent a lot of time playing computer games with my best friend. His family had a room full of computers. To me, they were irresistible. Magic. I spent many hours exploring all the games. One day I asked my friend, “how do we make a game?”
He didn’t know, so we asked his dad, who reached up on a high shelf and pulled down a book of games written in Basic. So began my journey with programming. By the time public school got around to teaching algebra, I already knew the topic well, because programming is basically algebra. It can be, anyway.
The Rise of Composable Software
In the beginning of computer science, before most of computer science was actually done on computers, there lived two great computer scientists: Alonzo Church, and Alan Turing. They produced two different, but equivalent universal models of computation. Both models could compute anything that can be computed (hence, “universal”).
Alonzo Church invented lambda calculus. Lambda calculus is a universal model of computation based on function application. Alan Turing is known for the turing machine. A turing machine is a universal model of computation that defines a theoretical device that manipulates symbols on a strip of tape.
Together, they collaborated to show that lambda calculus and the turing machine are functionally equivalent.
Lambda calculus is all about function composition. Thinking in terms of function composition is a remarkably expressive and eloquent way to compose software. In this text, we’re going to discuss the importance of function composition in software design.
There are three important points that make lambda calculus special:
const sum = (x, y) => x + yis the anonymous function expression
(x, y) => x + y.
- Functions in lambda calculus only accept a single input. They’re unary. If you need more than one parameter, the function will take one input and return a new function that takes the next, and so on. The n-ary function
(x, y) => x + ycan be expressed as a unary function like:
x => y => x + y. This transformation from an n-ary function to a unary function is known as currying.
- Functions are first-class, meaning that functions can be used as inputs to other functions, and functions can return functions.
The classic function composition takes the output from one function and uses it as the input for another function. For example, the composition:
f . g
Can be written as:
compose2 = f => g => x => f(g(x))
Here’s how you’d use it:
double = n => n * 2
inc = n => n + 1
compose2() function takes the
double function as the first argument, the
inc function as the second, and then applies the composition of those two functions to the argument
3. Looking at the signature of
3. The function call,
compose2(double)(inc)(3), is actually 3 different function invocations:
- The first passes
doubleand returns a new function.
- The returned function takes
incand returns a new function.
- The next returned function takes
f(g(x)), which is now
3and gets passed into
8gets returned from the function.
When software is composed, it can be represented by a graph of function compositions. Consider the following:
append = s1 => s2 => s1 + s2
You could represent it visually:
Lambda calculus was hugely influential on software design, and prior to about 1980, many very influential icons of computer science were building software using function composition. Lisp was created in 1958, and was heavily influenced by lambda calculus. Today, Lisp is the second-oldest language that’s still in popular use.
I was introduced to it through AutoLISP: the scripting language used in the most popular Computer Aided Design (CAD) software: AutoCAD. AutoCAD is so popular, virtually every other CAD application supports AutoLISP so that they can be compatible. Lisp is also a popular teaching language in computer science curriculum for three reasons:
- Its simplicity makes it easy to learn the basic syntax and semantics of Lisp in about a day.
- Lisp is all about function composition, and function composition is an elegant way to structure applications.
- The best computer science text book I know of uses Lisp: Structure and Interpretation of Computer Programs.
The Fall of Composable Software
Somewhere between 1970 and 1980, the way that software was created drifted away from simple compositions, and became a list of linear instructions for the computer to follow. Then came object-oriented programming — a great idea about component encapsulation and message passing that got distorted by popular languages into a horrible idea about inheritance hierarchies and is-a relationships for feature reuse.
Functional programming was relegated to the sidelines and academia: The blissful obsession of the geekiest of programming geeks, professors in their ivy league towers, and some lucky students who escaped the Java force-feeding obsession of the 1990’s — 2010's.
For most of us, creating software was a bit of a nightmare for 30 years. Dark times.
The Rise of Composable Software
Composition is a simple, elegant, and expressive way to clearly model the behavior of software. The process of composing small, deterministic functions to create larger software components and functionality produces software that is easier to organize, understand, debug, extend, test, and maintain.
As you read the following text, please experiment with the examples. Remember what it was like as a child to pick things apart, explore, and play while you learn. Rediscover the childhood joy of discovery. Let’s make some magic.
He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.