1. “Tout ce que vous avez
toujours voulu savoir sur la
programmation fonctionnelle*
*sans jamais oser le demander”
François Sarradin
Xebia IT
Architects
2. Programmation fonctionnelle
Ce qu'on en dit...
● "Bien pour la programmation concurrente"
● "Moins de bugs"
● To reduce cyclomatic complexity is far more important than to
reduce the number of LOCs. Incidentally FP gives a great help
to lower both -- @mariofusco
● "Un autre point de vue sur son langage quotidien"
● "Ça retourne le cerveau, pour le bien !"
3. Programmation fonctionnelle
Ce qu'on en dit aussi...
○ "Ellitiste"
○ "Difficile à apprendre"
○ "À ne pas mettre entre toutes les mains"
○ "Purement académique"
○ "Ça retourne le cerveau"
4. OK, mais...
Qu'est-ce que la
programmation fonctionnelle ?
5. Fonction Continuation
Lazy evaluation
Lambda calcul
Récursion Curryfication
Type
algébrique Combinateur de
Type system point fixe
Monade Programmation Ordre
Fonctionnelle supérieur
Monoïde
Closure
Functor Point free map/filter/
Pattern matching fold/zip
Inférence de type
Transparence
Catamorphisme référentielle Tail recursion
6. Au programme...
● La base du style fonctionnel
○ Histoire de la programmation fonctionnelle
○ Récursion / Ordre supérieur / Déterminisme
○ Optimisation
● Traitement de flux d'informations
○ Liste en programmation fonctionnelle
○ Fonctions sur listes
● Conclusion
● Hands On
7. Langages utilisés
● Haskell (principalement)
● Scala, Clojure, Erlang, etc.
● Java + Guava (pour le Hands On)
9. Soit la fonction factorielle
"n! est le produit des entiers compris entre 1 et n"
ou
n! = 1 * ⋯ * n
= Πi i , ∀ i ∈ [1..n]
ou
0! = 1,
n! = n . (n - 1)!, si n > 0.
10. Style
Fonctionnel
Impératif
int fact(int n):
result = 1
for i in [1..n]:
result = result * i
return result
(java)
public int fact(int n) {
if (n == 0) return 1;
(clojure) else return n * fact(n-1);
(defn fact [n] }
(reduce * 1
(range 1 (inc n))))
(erlang)
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
(haskell)
fact n = product [1..n]
11. Et aussi...
Point free
Composition de fonctions + disparition des variables
Continuation
Futur de la fonction en paramètre
Combinateur de point fixe
Permet les fonctions anonymes et récursives
Monade
Chaînage de traitements
12. Mais aussi des dérives...
APL (A Programming Language)
factorial←{
⍺←1
⍵=0:⍺
(⍺×⍵)∇ ⍵-1
}
life←{ ↑1 ⍵∨.^3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵ }
14. Tout est fonction
Au sens mathématique
f(x) = 2.x
x ↦ x + 42
h(x, y) = ∂2 p(x, y) / ∂x2
15. Fonction
Dans les langages fonctionnels
Haskell
identity x = x
x -> x
Scala
def identity(x: Any) = x
{ x: Any => x }
Clojure
(defn identity [x] x)
(fn [x] x)
16. Fonction
Avec Guava
new Function<T, R>() {
@Override
public R apply(T x) {
return x;
}
}
new Predicate<T>() {
@Override
public boolean apply(T x) {
return x == null;
}
}
25. Récursion
Proscrire Verboten ! def fact(n):
○ for r = 1
○ while for i in [1..n]:
○ repeat r *= i
○ etc. return n
Stateful !
Boucle = fonction qui s'appelle elle même
fact n = if n == 0
then 1
else n * fact (n-1)
31. Fonction d'ordre supérieur
Fonction en paramètre
Dérivée
deriv(f, x) = d f(x) / dt
Application d'une fonction sur chaque élément d'une
collection (Java 8 ?)
Arrays.asList(1, 2, 3).map(x -> x * x)
32. Fonction d'ordre supérieur
Fonction en sortie
Additionneur (curryfier)
add : x ↦ (y ↦ x + y)
add_one = add 1
add_one 2 => 3
add_one 10 => 11
34. Ordre supérieur
Apports
● Généricité / Réutilisation du code
● Extension du langage / DSL interne
// Scala
new Order to buy(100 sharesOf "IBM")
maxUnitPrice 300
using premiumPricing
new Order to sell(200 bondsOf "Sun")
maxUnitPrice 300
using {
(qty, unit) => qty * unit - 500
}
36. Indépendance / Déterminisme
f(x) = x + time() => NON !
f(x, t) = x + t => OUI !
● Fonction = Opération déclarative
○ Indépendante + sans état interne + déterministe
Une fonction retourne toujours la même valeur pourvu qu'on
lui fournisse les mêmes paramètres
=> Un bon point pour la programmation concurrente !
=> (+) de testabilité, (-) d'effet de bord
37. Immuabilité
x = x + 1 => NON !
y = x + 1 => OUI !
● Variable (fonctionnelle)
= variable (mathématique)
= constante (impératif)
= final (Java)
=> Encore un bon point pour la programmation concurrente !
=> (-) d'effet de bord
39. Optimisation
Style trampoline
Optimisation des fonctions récursives terminales
def fact(n, k):
if n == 0:
return k
return fact(n - 1, k * n)
devient
def fact(n, k):
while not (n == 0):
k = k * n
n = n - 1
return k
41. Optimisation
Flot de contrôle non linéaire
Si aucune dépendance ne les lient, 2 fonctions peuvent être
appelées dans n'importe quel ordre
Évaluation retardée
Èvaluation selon le besoin
Garbage collector
-- Since 1958 --
42. Sucre syntaxique
Inférence de type
Déterminer automatiquement le type d'une expression ou
d'une fonction
Pattern matching
Appliquer un traitement sur une valeur selon son "aspect"
=> switch-case on steroid!
value match { // Scala
case 1 => ...
case "hello" => ...
case x:Int => ...
case Symbol(a, b) => ...
}
44. Liste
Opérations de base (Haskell)
Liste de vide
[]
Ajouter un élément en tête
1 : [] == [1]
1 : [2, 3] == [1, 2, 3]
1 : 2 : 3 : [] == [1, 2, 3]
Récupérer la tête
head [1, 2, 3] == 1
Récupérer la queue
tail [1, 2, 3] == [2, 3]
46. Liste
Vers l'infini et au delà !
Haskell
[1..] => [1, 2, 3, 4, 5, ...
tail [1..] => [2, 3, 4, 5, 6, ...
take 3 [1..] => [1, 2, 3]
take 3 (drop 5 [1..]) => [6, 7, 8]
Scala
N/A
Clojure
(range 1) => (1 2 3 4 5 6 ...
47. Et en Java + Guava
Émuler les listes : iterator
Iterator<Integer> oneToFiveIterator
= new AbstractIterator<Integer>() {
private int i = 1;
@Override
protected Integer computeNext() {
if (i > 5) return endOfData();
else return i++;
}
};
// évaluation retardée selon Java !
48. Et en Java + Guava
Émuler les listes : iterable
Iterable<Integer> oneToFive
= new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator() {
return oneToFiveIterator;
}
};
assertThat(oneToFive)
.containsExactly(1, 2, 3, 4, 5);
49. Et en Java + Guava
Liste infinie : suite de 1
Iterator<Integer> onesIterator
= new AbstractIterator<Integer>() {
@Override
protected Integer computeNext()
{ return 1; }
}
Iterable<Integer> ones
= new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator()
{ return onesIterator; }
}
51. Fonction sur liste
map et filter
map
Applique une transformation sur chaque élément d'une liste
=> Guava : transform(iterable, function)
Haskell
map (+1) [1..5] => [2, 3, 4, 5, 6]
filter
Conserve que les éléments satisfaisant un prédicat
=> Guava : filter(iterable, predicate)
Haskell
filter (> 3) [1..5] => [4, 5]
52. Fonction sur liste
zip
zip
Fusionne deux listes
zipWith f [a1, ..., an] [b1, ..., bm] => [f(a1, b1), ..., f(an, bn)]
si n < m
Haskell
zipWith (+) [1..5] [6..8] => [7, 9, 11]
=> Pas d'équivalent en Guava
53. Fonction sur liste
fold/reduce
fold
Agrège les valeurs d'une liste (somme, produit, liste, ...)
foldl f a0 [b1, ..., bn]
=>
a1 <- f(a0, b1)
a2 <- f(a1, b2)
...
an-1<- f(an-2, bn-1)
return f(an-1, bn)
=> Pas d'équivalent en Guava
54. Fonction sur liste
fold/reduce
Haskell
foldl (+) 0 [1..5] => 15
product l = foldl (*) 1 l
fact n = product [1..n] = foldl (*) 1 [1..n]
reverse l = foldl (flip (:)) [] l
reverse [1..5] => [5, 4, 3, 2, 1]
56. Particularité
● Tout est fonction
○ Fonction sur des valeurs (1er ordre)
○ Fonction sur des fonctions (ordre supérieur)
○ Indépendance / Déterminisme / Immuabilité
● Optimisations diverses
● Récursion
● Traitement sur liste
Et plus encore...
57. Avantages
● Généricité / réutilisation / modularité
● Meilleure testabilité / fiabilité
● Adapter à la programmation concurrente
● Concision
Écrire du code avec un langage fonctionnel
= écrire des spécifications formelles
58. Difficulté
● Une façon de penser différente
● Courbe d'apprentissage
○ idiomes, patterns, best practices
● Longtemps enfermée dans la communauté scientifique
● Déclaratif
○ Pas de maîtrise du déroulement (plus qu'avec Java)
○ Bonne connaissance du compilateur/VM
● Trop de concision tue la lisibilité
59. Littérature
● Miran Lipovača, Learn You a Haskell for Great Good! (LYAH). Avril
2011. http://learnyouahaskell.com/
● Bryan O'Sullivan, Don Stewart, and John Goerzen, Real World Haskell
(RWH). Novembre 2008. http://book.realworldhaskell.org/
60. Congrès et User Groups
● International Conference on Functional Programming (ICFP), http:
//www.icfpconference.org/
● Commercial Users of Functional Programming (CUFP), http://cufp.org/
● Scala Days
● Clojure/conj
● Paris Scala User Group (soirée - 1/mois)
● Clojure Paris User Group (coding dojo - 1/semaine)
61. Sites webs
● Haskell : http://haskell.org/
○ API doc : http://haskell.org/ghc/docs/7.0-latest/html/libraries/index.
html
○ Web console : http://tryhaskell.org/
● Scala : http://www.scala-lang.org/
○ API doc : http://www.scala-lang.org/api/current/index.html#package
○ Web console : http://www.simplyscala.com/
● Clojure : http://clojure.org/
○ API doc : http://clojure.github.com/clojure/, http://clojuredocs.org/
○ Web console : http://try-clojure.org/
62. Hands On : ici...
https://github.com/fsarradin/xke-fp