Programs as Reductions
Eating the elephant one bite at a time
The to-do app was seeded with an initial state
{
view: "all",
next: 1,
todo: []
}
which requires a number of transformations to reach a stopping state:
{
view: "all",
next: 4,
todo: [
{id: 1, title: "Call mom", status: "completed"},
{id: 2, title: "Buy milk", status: "active"},
{id: 3, title: "Host movie night", status: "active"}
]
}
That’s what apps are. They faciliate action upon action against some data, some number of times, before stopping.
How do you eat an elephant? One bite at a time.
Starting from the beginning, at the browser console, let’s walk our atom forward one command at a time:
const $state = $.atom({
view: "all",
next: 1,
todo: []
});
Atom timeline
$.swap($state, addTodo("Call mom"))
{
view: "all",
next: 2,
todo: [
{id: 1, title: "Call mom", status: "active"}
]
}
$.swap($state, addTodo("Buy milk"))
{
view: "all",
next: 3,
todo: [
{id: 1, title: "Call mom", status: "active"},
{id: 2, title: "Buy milk", status: "active"}
]
}
$.swap($state, addTodo("Host movie night"))
{
view: "all",
next: 4,
todo: [
{id: 1, title: "Call mom", status: "active"},
{id: 2, title: "Buy milk", status: "active"},
{id: 3, title: "Host movie night", status: "active"}
]
}
$.swap($state, toggleStatus(1))
{
view: "all",
next: 4,
todo: [
{id: 1, title: "Call mom", status: "completed"},
{id: 2, title: "Buy milk", status: "active"},
{id: 3, title: "Host movie night", status: "active"}
]
}
$.swap($state, clearCompleted) //no configuration data
{
view: "all",
next: 4,
todo: [
{id: 2, title: "Buy milk", status: "active"},
{id: 3, title: "Host movie night", status: "active"}
]
}
This demonstrates, in addition to being a pure function, what a command is. It’s an algorithm with a direct and determinite correlation between the input and output data. Given the same arguments, a command can be trusted to yield the same result. Like a dictionary, it maps one value (a key that is some combination of input args) to another (a lookup value that is some result).
The snapshots flashing out from each command project a user story much like a movie reel projects images in quick succession on the silver screen. Programs are themselves little more than reductions. They start in an initial state and each command reduces it to the next.
To reinforce the analogy, see how easy it is to mold the above work session into a reduction. This form achieves the same net effect as the prior.
const init = {
view: "all",
next: 1,
todo: []
};
const commands = [
addTodo("Call mom"),
addTodo("Buy milk"),
addTodo("Host movie night"),
toggleStatus(1),
clearCompleted
];
const outcome =
commands.reduce((memo, command) => command(memo), init);
That programs could and should be seen as reductions was an epiphany for me. That’s what programs are: data processors. Data and operations. This changed my perspective on writing programs.
It’s surprising I should have this epiphany. In my day going into the field you got a Data Processing degree. That’s what I got. But somewhere along the way the simpler view of what programs did got supplanted by loftier ideas, as did the approaches to writing them, and “Computer Science” degrees became the norm. I still put on the object-oriented hat for certain parts of a program, but I find the functional hat and parts, and reductive thinking about computation more straightforward.
You see, every app starts seeded with data and necessitates a set of commands for getting its work done. Each issued command advances the story one step. It’s no wonder I felt so at home at the command line interacting with an atom. It’s just another mechanism for reducing state.
Through the lens of “programs as reductions,” I saw that every app was a command line at the beginning—or could be. I’ve provided a number of sample programs including puzzles and games using a reductive approach. You have also seen the programs in this book begin as an atom and some initial state. From there, you were told to get writing commands.
Apps are just dressed up command lines. So phase one is working out the commands—that is, the reduction held by the core. As with command line commands, some take args. Some don’t.
And what’s so gratifying is, at this stage, there are no sharp edges to get cut on. The difficult parts of programming have been reserved for the imperative shell, and that won’t be started until the core is more fully formed.
You’ll see, once you get the hang of it, what a pleasure it is to code this way. Things here are straightforward. The problems much less daunting.
ML