|
ilja
eb1ef83e79
First draft and examples
The examples are the first three days of Advent Of Code There's still some notes, but I think the (5) rules we have are already good |
||
|---|---|---|
| 1.js | First draft and examples | |
| 2.js | First draft and examples | |
| 3.js | First draft and examples | |
| README.md | First draft and examples | |
Function Calesthenics - Challenge
When I got into programming, it was mostly focussed on OOP. Something I discovered was Object Calisthenics. The idea is that you write a program following a set of specific rules. The rules are things like "wrap all primitives and strings", "don't use any classes with more than two instance variables", "don't use the ELSE keyword"... The reasoning is that by doing this, you force yourself to think in a more OOP way.
Later I got used to a more functional way of programming and wondered if a similar thing exists for functional programming. I don't find it online, so I decided to try some rules myself.
This repository contains solutions for the first three days of 2023 advent of code where I restricted myself to the rules I came up with for Function Calesthenics. The language I used is Javascript because it's a popular language these days and because I wanted a language that's not a typical functional language by itself. I must admit, however, that I find the readability in a more functional language like Elixir is much better for this than Javascript.
I don't have enough theoretical background to really decide if the rules make much sense, or if more should be added, so if you have insights into that, don't hesitate to provide feedback <3
The rules
These are the rules I came up with. Feedback, especially on the below notes, is welcome.
NOTE: I'm unsure if setting default parameter values should be allowed, in my code I made sure to not do it, but I'm unsure if this restriction really helps you think more functionally. At the moment it's not a rule.
NOTE: I'm also wondering if I should set a rule to "use/chain 'reduce', 'filter', and 'map'" a lot. But I'm not sure how to properly word this. ("a lot" isn't really a proper way to word it imo)
NOTE: I think I also need a rule to keep functions small. Object Calisthenics does this with the rule "only one level of indentation per method". Maybe we need something similar here? Although I feel that this already happens by not allowing assignements.
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.
The following is forbidden because you are using assignments let userid = userobj.id and let username = userobj.name.
do_something = fun(userobj){
let userid = userobj.id
let username = userobj.name
return do_something_with_this(userid, username)
}
The following is allowed because the only assignment is because it's required to define our named function.
do_something = fun(userobj){
return do_something_with_this(
userobj.id,
userobj.name
)
}
2. Don't use mutability
If your object is mutable, then the following case is not allowed because it requires an assignment.
object.name = "a cool name"
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.
Assuming object.set_name in the following example mutates the object, it is not allowed.
object.set_name("a cool name")
3. No imperative for/while/if/else/switch/case structures allowed
The idea of a function in functional programming, is really in the mathmatical sense that you have an inptut who maps to an output. Imparative 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.
The following is not allowed
if (is_even(number)) {
"yup, it's even alright"
} else {
"that's so odd, I can't even"
}
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. 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
Functions in functional programming are really functions in the mathmatical sense. You have a set of possible input, a set of possible outputs, and you "map" an input to an output.
In mathmatics, it's someties written something like this
addition: Real Numbers x Real Numbers -> Real Numbers: a, b |-> a + b
Reading/writing something from/to in-/output or a databse, 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
console.log(
MyFunctionalModule.echo(
console.input("tell me what to echo")
)
)
License
The Advent of Code challenges belong to their respective owner. The code can be considered AGPL-v3.