Long ago, I discovered something called Object Calisthenics. The idea is that you write a program following a set of specific rules. The limitations these rules bring, force you to think in a more OOP way.
A year a go I wondered if a similar thing existed for Functional Programming. I didn't find anything, so I decided to try something myself, see https://codeberg.org/ilja/function_calesthenics
I hereby share it, so others who may be interested can check it out, and give thoughts and feedback. Do these rules make sense for the stated goal? Are there other things I should add to push for a more functional way of thinking? Are there rules who don't make sense at all? Or are there other adaptions who could improve it? Do you think it's an interesting exercise to begin with? If you tried it, do share your experiences!
In short, the challenge is the following; Write a program (doesn't have to be big), keeping the following limitations in mind.
1. assignments are not allowed
If your language requires assignments to define named functions and/or modules, then you are allowed to use assignments for that and only for that. And you should never re-define the variable you assigned the function/module to.
2. Don't use mutability
Assignments are not allowed, but if your object allows mutability through methods, you can work around that by claiming that you aren't actually using an assignment. This is false because inside the method you called, you are still doing an assignment. This rule makes it explicit that this is not allowed.
3. No imperative for/while/if/else/switch/case structures allowed
The idea of a function in functional programming, is really in the mathematical sense that you have an input who maps to an output. Imperative structures like for/while/if/else/switch/case don't do that. They tell your code "in this case, do this. In that case, do that", but they do not map an input on an output.
In functional languages, there is often also an if
structure. Unlike the imperative counterpart, this structure does map an input on an output, making it an actual function. This is an example of how it could look, and this is allowed.
if(is_even(number), function(){return "yup, it's even alright"}, function(){return "that's so odd, I can't even"})
For loops, you can often make use of, and even chain, things like reduce
, filter
, or map
(if you don't know these things, let me shamelessly link to an article where i explain these ). Another option is using recursion.
4. no repetition
Our code needs to remain somewhat clean. When we do something, we only do it once. The following is not allowed because we do the work str.split(":")
twice.
break_string(str) {
return {
first_part: str.split(":")[0],
second_part: str.split(":")[1]
}
}
break_string("something:something else")
When you see that, it just screams at you to use an assignment like var splitted_string = str.split(":")
, doesn't it. You aren't allowed to use an assignment, so that's not possible. But you are also not allowed to get away with it so easily. This rule forces you to think a bit more about how to handle this situation.
5. Only pure functions are allowed
As mentioned before, functions in functional programming are really functions in the mathematical sense. You have a set of possible input, a set of possible outputs, and you "map" an input to an output.
Reading/writing something from/to in-/output or a database, is not a function. Randomised output isn't possible in a function. Of course, these things are often required in a program. As such we will only allow it if you keep it on "the edges" of your program. Basically, write the "core" of your application in a functional way, then call that.
The following would be allowed
// This is the "core" of the program, where all the real logic happens
// This is purely functional
MyFunctionalModule {
def echo(str){
return str
}
}
// Here we read and write from/to the console, and then call our functional program
// The non-functional things happen here, only here, and these are the only things allowed to happen here
console.log(
MyFunctionalModule.echo(
console.input("tell me what to echo")
)
)