62
“Tout ce que vous avez toujours voulu savoir sur la programmation fonctionnelle* *sans jamais oser le demander” François Sarradin Xebia IT Architects

Programmation Fonctionnelle

Embed Size (px)

Citation preview

Page 1: Programmation Fonctionnelle

“Tout ce que vous aveztoujours voulu savoir sur la

programmation fonctionnelle**sans jamais oser le demander”

François Sarradin

Xebia ITArchitects

Page 2: Programmation Fonctionnelle

● "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 !"

Programmation fonctionnelleCe qu'on en dit...

Page 3: Programmation Fonctionnelle

○ "Ellitiste" ○ "Difficile à apprendre" ○ "À ne pas mettre entre toutes les mains" ○ "Purement académique" ○ "Ça retourne le cerveau"

Programmation fonctionnelleCe qu'on en dit aussi...

Page 4: Programmation Fonctionnelle

OK, mais...

Qu'est-ce que laprogrammation fonctionnelle ?

Page 5: Programmation Fonctionnelle

Récursion

Fonction

Monade

Monoïde

Lazy evaluation

Tail recursion

Curryfication

Point freePattern matching

ProgrammationFonctionnelle

Combinateur de point fixe

Continuation

Closuremap/filter/fold/zip

Lambda calcul

Inférence de type

Catamorphisme

Type system

Functor

Ordre supérieur

Type algébrique

Transparence référentielle

Page 6: Programmation Fonctionnelle

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

Page 7: Programmation Fonctionnelle

● Haskell (principalement) ● Scala, Clojure, Erlang, etc.

● Java + Guava (pour le Hands On)

Langages utilisés

Page 8: Programmation Fonctionnelle

Commençons

Page 9: Programmation Fonctionnelle

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.

Page 10: Programmation Fonctionnelle

StyleFonctionnel

int fact(int n): result = 1 for i in [1..n]: result = result * i return result

fact n = product [1..n](haskell)

Impératif

(defn fact [n] (reduce * 1 (range 1 (inc n))))

(clojure)

fact(0) -> 1;fact(N) -> N * fact(N - 1).

(erlang)

public int fact(int n) { if (n == 0) return 1; else return n * fact(n-1);}

(java)

Page 11: Programmation Fonctionnelle

Et aussi...

Point freeComposition de fonctions + disparition des variables ContinuationFutur de la fonction en paramètre Combinateur de point fixePermet les fonctions anonymes et récursives MonadeChaînage de traitements

Page 12: Programmation Fonctionnelle

Mais aussi des dérives...

factorial←{⍺←1⍵=0:⍺(⍺×⍵)∇ ⍵-1

}

life←{ ↑1 ⍵∨.^3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵ }

APL (A Programming Language)

Page 13: Programmation Fonctionnelle

Programmation fonctionnellePrincipe n°1 : tout est fonction

Page 14: Programmation Fonctionnelle

Tout est fonctionAu sens mathématique

f(x) = 2.x

x ↦ x + 42

h(x, y) = ∂2 p(x, y) / ∂x2

Page 15: Programmation Fonctionnelle

FonctionDans les langages fonctionnels

Haskellidentity x = x\x -> x

Scaladef identity(x: Any) = x{ x: Any => x }

Clojure(defn identity [x] x)(fn [x] x)

Page 16: Programmation Fonctionnelle

FonctionAvec 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; }}

Page 17: Programmation Fonctionnelle

Programmation fonctionnelleD'où est-ce que ça vient ?

Page 18: Programmation Fonctionnelle

Fonction mathématiquefin du XVIIe siècle

f : x ↦ x f : x ↦ 2 . x

ou

f(x) = 2 . xGottfried Wilhelm von Leibniz(1646-1716)

Page 19: Programmation Fonctionnelle

λx.x(λx.2*x) 7 → 2 * 7 true ::= λxy.xfalse ::= λxy.yif-then-else ::= λpab.p a b 0 ::= λfx.x1 ::= λfx.f x2 ::= λfx.f (f x)

Lambda-calcul1936

Alonzo Church(1903-1995)

Page 20: Programmation Fonctionnelle

(lambda (x) x)(f arg1 arg2 ...)(lambda (x) (* 2 x)) (cons A B)(car (cons A B)) => A(cdr (cons A B)) => B

LISP1958

John McCarthy (1927-2011)

Page 21: Programmation Fonctionnelle

Et ensuite...

Lisp (1958) Scheme (1975) Common Lisp (1984) Clojure (2007)

APL (1964) FP (1977) J (1990)

ISWIM (1966) ML (1973) Caml (1985) F# (2002) Haskell (1987) Scala (2003)

Forth (1970s) PostScript (1982) RPL (1984) Joy (2001)

Prolog (1972) Erlang (1986)

Page 22: Programmation Fonctionnelle

Version "embarqué"

● Langage○ Java 8 (en 2012 ?)○ Groovy○ Python○ Ruby○ SmallTalk○ ...

● API Java

○ Guava○ LambdaJ○ TotallyLazy○ FunctionalJava○ FunkyJFunctional

Page 23: Programmation Fonctionnelle

Success stories

● Banque / finance○ Jane Street (OCaml)○ Goldman Sachs (Erlang), CitiGroup (Clojure), ...

● Réseaux sociaux○ Twitter (Scala)○ FourSquare (Scala/Lift)○ Facebook (Erlang)

● Télécommunication○ Ericsson (Erlang)

● Autres...○ Microsoft (F#)○ CouchDB, RabbitMQ (Erlang)

Page 24: Programmation Fonctionnelle

Programmation fonctionnellePrincipe n°2 : récursion

Page 25: Programmation Fonctionnelle

Récursion

Boucle = fonction qui s'appelle elle même fact n = if n == 0 then 1 else n * fact (n-1)

Proscrire ○for○while○repeat○ etc.

Verboten !

Stateful !

def fact(n):r = 1for i in [1..n]:

r *= ireturn n

Page 26: Programmation Fonctionnelle

Récursion terminale

L'appel récursif est la dernière instructionfact_t n k = if n == 0 then k else fact_t (n-1) (n*k) fact n = fact_t n 1

Page 27: Programmation Fonctionnelle

Récursion : pile d'appels

-> fact(5) -> fact(4) -> fact(3) -> fact(2) -> fact(1) -> fact(0) <- 1 <- 1 * 1 = 1 <- 2 * 1 = 2 <- 3 * 2 = 6 <- 4 * 6 = 24<- 5 * 24 = 120

fact n = if n == 0 then 1 else n * fact (n-1)

Page 28: Programmation Fonctionnelle

Récursion terminale : pile d'appels

-> fact_t 5 1 -> fact_t 4 5 -> fact_t 3 20 -> fact_t 2 60 -> fact_t 1 120 -> fact_t 0 120 <- 120 <- 120 ...<- 120

fact_t n k = if n == 0 then k else fact_t (n-1) (n*k)

Page 29: Programmation Fonctionnelle

Récursion : beware !

Page 30: Programmation Fonctionnelle

Programmation fonctionnellePrincipe n°3 : ordre supérieur

Page 31: Programmation Fonctionnelle

Fonction d'ordre supérieurFonction en paramètre

Dérivéederiv(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)

Page 32: Programmation Fonctionnelle

Fonction d'ordre supérieurFonction en sortie

Additionneur (curryfier)add : x ↦ (y ↦ x + y)

add_one = add 1

add_one 2 => 3add_one 10 => 11

Page 33: Programmation Fonctionnelle

Fonction d'ordre supérieur... ou les deux

Compositionf ∘ g : x ↦ f(g(x))

Page 34: Programmation Fonctionnelle

● Généricité / Réutilisation du code● Extension du langage / DSL interne

// Scalanew 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 }

Ordre supérieurApports

Page 35: Programmation Fonctionnelle

Programmation fonctionnellePrincipe n°4 : déterminisme

Page 36: Programmation Fonctionnelle

● 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

Indépendance / Déterminisme

f(x) = x + time() => NON !f(x, t) = x + t => OUI !

Page 37: Programmation Fonctionnelle

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

Immuabilité

Page 38: Programmation Fonctionnelle

Programmation fonctionnelleDéterminisme => Optimisation

Page 39: Programmation Fonctionnelle

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

OptimisationStyle trampoline

Page 40: Programmation Fonctionnelle

Transparence référentielleUne expression peut être remplacée par son résultat sans changer le comportement du programme MémoizationConserver en cache le résultat d'une fonction selon ses paramètres

Optimisation

Page 41: Programmation Fonctionnelle

Flot de contrôle non linéaireSi 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 --

Optimisation

Page 42: Programmation Fonctionnelle

Inférence de typeDéterminer automatiquement le type d'une expression ou d'une fonction Pattern matchingAppliquer 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) => ...}

Sucre syntaxique

Page 43: Programmation Fonctionnelle

Programmation fonctionnellePrincipe n°5 : liste

Page 44: Programmation Fonctionnelle

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]

ListeOpérations de base (Haskell)

Page 45: Programmation Fonctionnelle

ListeFinie

Haskell[1,2,3,4,5] => [1, 2, 3, 4, 5][1..5] => [1, 2, 3, 4, 5]['a'..'z'] => "abcdefghijklmnopqrstuvwxyz" Scala(1 to 5) => Range(1, 2, 3, 4, 5)('a' to 'z') => NumericRange(a, b,[...], y, z) Clojure(range 1 5) => (1 2 3 4)

Page 46: Programmation Fonctionnelle

ListeVers 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] ScalaN/A Clojure(range 1) => (1 2 3 4 5 6 ...

Page 47: Programmation Fonctionnelle

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 !

Et en Java + GuavaÉmuler les listes : iterator

Page 48: Programmation Fonctionnelle

Iterable<Integer> oneToFive = new Iterable<Integer>() { @Override public Iterator<Integer> iterator() { return oneToFiveIterator; } }; assertThat(oneToFive)

.containsExactly(1, 2, 3, 4, 5);

Et en Java + GuavaÉmuler les listes : iterable

Page 49: Programmation Fonctionnelle

Et en Java + GuavaListe 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; }}

Page 50: Programmation Fonctionnelle

Programmation fonctionnelleOpérations de traitement sur listes

Page 51: Programmation Fonctionnelle

mapApplique une transformation sur chaque élément d'une liste

=> Guava : transform(iterable, function)

Haskellmap (+1) [1..5] => [2, 3, 4, 5, 6]

filterConserve que les éléments satisfaisant un prédicat

=> Guava : filter(iterable, predicate)

Haskellfilter (> 3) [1..5] => [4, 5]

Fonction sur listemap et filter

Page 52: Programmation Fonctionnelle

Fonction sur listezip

zipFusionne deux listes

zipWith f [a1, ..., an] [b1, ..., bm] => [f(a1, b1), ..., f(an, bn)]si n < m HaskellzipWith (+) [1..5] [6..8] => [7, 9, 11]

=> Pas d'équivalent en Guava

Page 53: Programmation Fonctionnelle

foldAgrè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

Fonction sur listefold/reduce

Page 54: Programmation Fonctionnelle

Fonction sur listefold/reduce

Haskellfoldl (+) 0 [1..5] => 15 product l = foldl (*) 1 lfact n = product [1..n] = foldl (*) 1 [1..n] reverse l = foldl (flip (:)) [] lreverse [1..5] => [5, 4, 3, 2, 1]

Page 55: Programmation Fonctionnelle

En résuméLa programmation fonctionnelle, c'est...

Page 56: Programmation Fonctionnelle

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...

Page 57: Programmation Fonctionnelle

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

Page 58: Programmation Fonctionnelle

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é

Page 59: Programmation Fonctionnelle

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/

Page 60: Programmation Fonctionnelle

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)

Page 61: Programmation Fonctionnelle

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/

Page 62: Programmation Fonctionnelle

Hands On : ici...

https://github.com/fsarradin/xke-fp