Object Calisthenics helps people to become better Object-Oriented programmers and as someone new(ish) to the functional world I wondered if there were an equivalent set of rules that would help me become a better functional programmer, so I asked the people at SoCraTes UK 2015:
What are Functional Calisthenics? They are derived from Object Calisthenics, these rules that you can apply to make your object-oriented code better by applying strict rules in what you can and cannot do. These strict rules force you to think differently about how to write your code, e.g. the rule No getters of setters will often lead to people thinking If I can't get at the internal state using a getter, how can I test that the current state is correct? I was wondering whether there was something similar that I could use as a training exercise to improve my functional programming and escape an "object-oriented mindset".
So, I asked the wonderful community at the SoCraTes UK 2015 conference about them, there was a huge amount of interest and a lot of people enthusiastically helped to come up with these initial thoughts on our Functional Calisthenics.
We want the majority of our code to be pure functions and in order for that to be the case they cannot depend on anything that is impure. This means we should pull the impure functions up to the top level and isolate them as much as possible from the rest of the code. This can include:
This is very close to the Side effects can only occur at the top level rule but we can go further than just creating pure functions, we don't want to mutate state within a function either, e.g. do not re-use variables (if your language allows) as this has a negative impact on code readability and any mutable state could potentially result in an unintended consequence.
This is a kind of extension of the No mutable state rule, if we are calling a function that does not return anything then we are probably expecting that some mutable state will be changes as a part of this call and the function will not be pure. If we are aiming for purity then we should only be using functions that take return values.
This is one that is probably causing a fair amount of debate, but we should be using restricting the number of arguments that a function can take, a function with a large number of arguments smells of a single responsibility principle violation. Currying provides us with the ability to reduce long argument lists to a series of functions that all take one parameter.
Prefer separating the method of recursion away from the logic that you are trying to execute.
Functions should take the highest level of abstraction possible, e.g. if List is a special case of Enumerable then the function should take Enumerable.
If you function takes, or returns, a sequence of data then write the function in a way that does not exclude infinite sequences, allow for tail recursion etc.
Avoid using if statements where possible. As Samir said
"if" is just a special case of pattern matching anyway
We should provide named types for primitives including tuples and we should avoid anoymous functions and lambdas.
Avoid chaining function calls, extract into intermediate variables.
Let's be fair, we've all seen functional code with functions like f(), we're not in the dark ages people and we can afford to use more descriptive names to help those who come along later to understand the intent of the code.
Thse are all preliminary ideas that could help people learn and grow their knowledge of functional programming, they are barely 9 hours old as I write this and we have had our first tentative steps in applying these rules to a code kata. The next step is to try Functional Calisthenics in code katas, see what works, what doesn't are there other rules that would help produce better functional programmers. The discussion is just beginning.
I could not have come up with these rules without those who attended my session at the SoCraTes UK 2015 conference, I may have had an idea but they have taken the concept and fleshed it out to where we are now and hopefully together we will continue to develop these ideas for the benefit of the community.