10. Functions are First Class citizens
○ The ability to treat functions as values
○ The ability to pass those values into other functions
○ Being able to write small snippets of code as anonymous functions
○ Not having to create deep hierarchies of classes (that sometimes feel “artifical”)
○ Most FP languages are “low ceremony” languages, meaning that they require less
boilerplate code than other languages
19. Pure functions are easier to reason about
First, pure functions are easier to reason about because you know that they can’t do certain things, such as talk to the
outside world, have hidden inputs, or modify hidden state. Because of this, you’re guaranteed that their function signatures
tell you (a) exactly what’s going into each function, and (b) coming out of each function.
In his book, Clean Code (affiliate link), Robert Martin writes:
“The ratio of time spent reading (code) versus writing is well over 10 to 1 ... (therefore) making it
easy to read makes it easier to write.”
I suspect that this ratio is lower with FP. Because pure functions are easier to reason about:
● I spend less time “reading” them.
● I can keep fewer details in my brain for every function that I read.
This is what functional programmers refer to as “a higher level of abstraction.”
20. Dishonest function (1)
function x() { … }
que fait - elle ?
https://enterprisecraftsmanship.com/posts/what-is-functional-programming/
21. Dishonest function (2): referentially
transparent.
A referentially transparent function always produces the same result as long as you supply it the same
arguments. It means that such function should operate only the values we pass in, it shouldn’t refer to the global
state.
Here’s an example:
public long TicksElapsedFrom(int year)
{
DateTime now = DateTime.Now;
DateTime then = new DateTime(year, 1, 1);
return (now - then).Ticks;
}
22. Dishonest function (2): referentially
transparent.
public long TicksElapsedFrom(int year)
{
DateTime now = DateTime.Now;
DateTime then = new DateTime(year, 1, 1);
return (now - then).Ticks;
}
This method is not referentially transparent because it returns different results even if we pass it the
same year. The reason here is that it refers to the global DatetTime.Now property.
23. Dishonest function (2): referentially
transparent.
A referentially transparent alternative for this method would be:
public long TicksElapsedFrom(int year, DateTime now)
{
DateTime then = new DateTime(year, 1, 1);
return (now - then).Ticks;
}
24. Dishonest function (3): method signature
honesty.
public int Divide(int x, int y)
{
return x / y;
}
The Divide method, despite being referentially transparent, is not a mathematical function. Its signature
states that it accepts any two integers and returns another integer. But what happens if we pass it 1 and
0 as input parameters?
25. Dishonest function (3): method signature
honesty.
public int Divide(int x, int y)
{
return x / y;
}
S
SOLUTION ???
26. Dishonest function (3): method signature
honesty.
public static int Divide(int x, NonZeroInteger y)
{
return x / y.Value;
}
27. Dishonest function (3): method signature
honesty.
public static int ? Divide(int x, int y)
{
if (y == 0)
return null;
return x / y;
}
This version is also honest as it now doesn’t guarantee that it will return an integer for any possible
combination of input values.
28. Dishonest function (4): exceptions
Exceptions
Exceptions is another source of dishonesty for your code base. Methods that employ exceptions to
control the program flow are not mathematical functions because, just like side effects, exceptions hide
the actual outcome of the operation the method performs.
Moreover, exceptions have a goto semantics meaning that they allow you to easily jump from any point
of your program to a catch block. In fact, exceptions perform even worse because the goto statement
doesn’t allow for jumping outside a particular method, whereas with exceptions you can cross multiple
layers in your code base with ease.
29. Dishonest function (4): exceptions
Because functional programming is like algebra, there are no null values or exceptions. But of course you can still have
exceptions when you try to access servers that are down or files that are missing, so what can you do?
Option/Some/None
Try/Success/Failure
def toInt(s: String): Option[Int] = {
try {
Some(Integer.parseInt(s.trim))
} catch {
case e: Exception => None
}
def toInt(s: String): Try[Int] = Try {
Integer.parseInt(s.trim)
}
toInt(x) match {
case Success(i) => println(i)
case Failure(s) => println(s"Failed. Reason: $s")
}
31. Dishonest function (5): effets de bord
The first such practice is avoiding side effects as much as possible by employing immutability all over your code base. This
technique is important because the act of mutating state contradicts the functional principles.
The signature of a method with a side effect doesn’t communicate enough information about what the actual result of the
operation is, and that hinders our ability to reason about it. In order to validate your assumptions regarding the code you
are writing, not only do you have to look at the method’s signature itself, but you also need to fall down to its
implementation details and see if this method leaves any side effects that you didn’t expect.
32. Dishonest function (5): effets de bord
Overall, code with data structures that change over time is harder to debug and is more error-prone. It brings even more
problems in multi-threaded applications where you can have all sorts of nasty race conditions.
When you operate immutable data only, you force yourself to reveal hidden side effects by stating them in the method’s
signature and thus making it honest. This makes the code more readable because you don’t have to fall down to the
methods' implementation details in order to reason about the program flow. With immutable classes, you can just look at
the signature of a method and get a good understanding of what is going on right away, without too much effort.
33. Avoid nulls
Another practice in this list is avoiding nulls. It turns out that the use of nulls makes your code dishonest
as the signature of the methods using them doesn’t tell all information about the possible outcome the
corresponding operation may have.
34.
35.
36.
37.
38. Testing is easier, and pure functions lend
themselves well to techniques like property-
based testing
https://alvinalexander.com/scala/fp-book/benefits-of-functional-programming/#testing-is-easier-and-pure-
functions-lend-themselves-well-to-techniques-like-property-based-testing
42. Quelles différences?
On the scale of abstraction, the Turing Machine sits at one end, where Lambda
Calculus sits at the other.
Two extremes, yet with lots in common:
there is no problem one can solve that the other one cannot.
https://www.eonics.nl/story/functional-programming-part-1-historical-context/
43. Avantages
1. Pure functions are easier to reason about
2. Testing is easier, and pure functions lend themselves well to techniques like property-
based testing
3. Debugging is easier
4. Programs are more bulletproof
5. Programs are written at a higher level, and are therefore easier to comprehend
6. Function signatures are more meaningful
7. Parallel/concurrent programming is easier
44. Take away
● Paramètres de fonction plutôt que données globales (même de classe)
● Créer des objets plutôt que de les modifier (immutable)
● Option plutôt que ‘null’
● Option / Try / Either / Result ... (monads) plutôt qu’une exception
● Collection API / récursivité plutôt que boucles for/while
● Eviter les ‘if’ autant que possible
● Séparation technique / métier
● Functionnal core / Imperative shell
https://www.slideshare.net/loicknuchel/comprendre-la-programmation-fonctionnelle-blend-web-mix-le-02112016/60