What is Functional Programming?

Search for a command to run...

No comments yet. Be the first to comment.
In our previous post, we introduced how to utilize Discrete Event Simulation (DES) in PicoLisp. Now, let's explore another application: a railroad model simulation that includes tracks and trains. The visualization is ASCII-based, so feel free to unl...

The Dining Philosophers

In this post, we will introduce the concept of co-routines and how they are handled in PicoLisp. This will be the foundation for the subsequent posts on Discrete Event Simulation and finally a couple of examples, including an ASCII model railway simu...

One of the many nice things of PicoLisp is that it comes with a built-in database. This makes it easy to collect and store our own data, for example via a mobile app. But not all data is best represented in tables and lists: sometimes a colorful litt...

In the last two posts, we have built a little app that shows the current location and displays the nearest ice cream shops: https://picolisp-explored.com/an-openstreetmap-app-written-in-picolisp-pt-1 https://picolisp-explored.com/an-openstreetmap-ap...

Given that this blog is called "Functional Programming in PicoLisp", I think we should now finally clarify what functional programming actually means.
In this post, I want to introduce two definitions: First the fairly academic one that can be found anywhere, like for example on Wikipedia, and a more hands-on definition by Eric Normand from lispcast.com.
As Wikipedia tells us, functional Programming is a paradigm where programs are constructed by applying and composing functions. Functions can be passed on and returned from functions just like any kind of data ("first-class citizen").
To me, this is a typical example of a self-referencing definition that doesn't help at all. "Functional programming uses functions", thank you. Let's reframe the question:
The term "Functions" is quite commonly used in programming, but unfortunately in a slightly different meaning. This makes it quite confusing.
In the context of many programming languages, functions are simply "sets of instructions bundled together to achieve a specific outcome, in order to avoid repetitive blocks". According to this definition, we can consider for example object methods in Java also as "functions".
Unfortunately, this is not precisely what we mean by "functions" in the context of "Functional Programming".
In the context of functional programming, the idea of functions is closer to the original, mathematical context: A function "takes" in arguments and "returns" a result.
If it is a pure function, it additionally fulfills the following two conditions:
Let's return to the initial definition:
Functional Programming is a paradigm where programs are constructed by applying and composing functions. Functions can be passed on and returned from functions just like any kind of data ("first-class citizen").
Now we know that functions always have input and return values, and if possible, no side-effects. But still it doesn't tell us much about how such a paradigm can look like, right?
I think the main problem with these kind of definitions is that terms like "functions", "side-effects", "first-class" already have different meanings in other contexts, which makes the terminology so unclear and fuzzy. This is why I really like the definition from Eric Normand, because the wording is much less ambiguous:
"Functional programming is a programming style where you make a clear distinction between actions, calculations, and data."
Again, let's clarify the terminology first. Unlike terms like "functions" and "side-effects", the definitions for "data, calculations and actions" are much more compliant with what you'd expect.
Data are basically facts, or more precisely: "recorded facts about events". Data is not executable. For example, this is data: ["abc", "def"], 27.11.2021, {name: "Mia"}.
Calculations always give the same output for the same input. It doesn't change if you run the calculation one time or 200 times.
Actions is anything that depends on when it is run, or how many times it is run. Examples: sending emails, getting the current timestamp, deleting an object from the database...
Now, if you compare that to our first definition, you will see that "calculations" correspond to "pure functions" and "actions" correspond to "side-effects", only that it is intuitively more clear what is meant.
Let's look at an example to show what it means to differentiate between data, calculations and actions. I think it's easier to demonstrate this on a bad example.
This is the functionality we want to implement: Say we have a form sheet where the user can change their nickname. If that happens, we update the user data, then we save it to the database and send a confirmation email.
What do you think of this?
The following code is meant as a kind of JavaScript pseudocode. Please don't take it literally.
var currentUser = { firstName: "Tom", lastName: "Miller", nickname: "tommy", email: "tom@miller.com" }
function updateUserNickname( newName ) {
currentUser.nickname = newName;
currentUser.saveToDatabase();
sendConfirmationEmail( GlobalUser.email );
}
// Run it
updateUserNickname("tom");
I'm sure you agree with me that this is not very elegant. But let's try to figure out what is the problem. First of all, we try to distinguish between calculation, data and actions.
currentUser,updateUserNickname, saveToDatabase, sendConfirmationEmail Do you see the problem? Inside our function updateUserNickname, we have a wild mix of different things. We modify the global user data, we save it to the database and we send a confirmation email. This causes a number of problems. Let's sort them by category:
Testing and debugging:
updateUserNickname, we also need to simulate the database savings and confirmation emails.Maintainability:
Concurrency Problem:
CurrentUserdisplays the new value.We learned that functional programming prefers to separate calculations and actions, and avoids to directly mutate data. Let's try!
Disclaimer, again: This example is just for the sake of illustration. Don't take it literally.
var currentUser = {firstName: "Tom", lastName: "Miller", nickname: "tommy", email: "tom@miller.com"}
updateObj(obj, key, value) {
obj[key] = value;
return obj;
}
saveUpdate(obj) {
if (obj.saveToDatabase() == successful)
return true; // alternatives: return database ID, user object etc.
else
return false;
}
// run it
var updatedUser = updateObj(currentUser, "nickname", "tom")
if (saveUpdate(updatedUser)) {
sendConfirmationEmail(updatedUser.email);
}
In functional programming, we aim to create functions without side effects that are as reusable (i. e. generic) as possible. This means we have to separate actions from calculations.
We split our updateUser() function into three parts:
updateObject, which is a calculation (no side effects, return value)saveUpdate, which is an action and also returns a value,sendConfirmationEmail, which executes based on the return value of saveUpdate.The second "functional" change is that we don't modify the global variable currentUser directly ("immutability"). Instead we created a local variable updatedUser which holds the changes. We could write it back to currentUser once all actions have finished successfully.
Now, of course data, calculations and actions are always part of any program. The separation we illustrated above also has nothing to do with the programming language itself, because it's basically a way of coding and thinking.
Nevertheless, some languages make it more easy to follow this kind of paradigm than others. Imperative languages usually require the programer to define precisely how to accomplish a certain task: with loops, conditional statements, breaks and so on. These can be already considered as "actions", which means that it requires a lot of effort and abstraction to separate data, calculations and actions cleanly.
In functional languages like PicoLisp, this can be much easier: For example in PicoLisp, every function has a return value by default. There is no need to define one explicitly. Also, functions can be used as input and return values, which allows more powerful constructs than our pseudocode above.
In the next post, we will highlight some of the functional programming features of PicoLisp.
Eric Normand: Thoughts on Functional Programming
Eric Normand: Grokking Simplicity: Taming Complex Software with Functional Thinking (Manning 2021)
https://www.guru99.com/functional-programming-tutorial.html
https://en.wikipedia.org/wiki/Functional_programming
https://en.wikipedia.org/wiki/Pure_function