Programmation fonctionnelle

46
La programmation fonctionnelle En 45 minutes Raphael Javaux

Transcript of Programmation fonctionnelle

Page 1: Programmation fonctionnelle

La programmation fonctionnelleEn 45 minutes

Raphael Javaux

Page 2: Programmation fonctionnelle

Plan

● Kesako ?● Haskell

○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin

Page 3: Programmation fonctionnelle

Plan

● Kesako ?● Haskell

○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin

Page 4: Programmation fonctionnelle

>>> xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]>>> map(lambda x: x * x, xs)[1, 4, 9, 16, 25, 36, 49, 64, 81]

Kesako ?

λ ?

Page 5: Programmation fonctionnelle

>>> xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]>>> map(lambda x: x * x, xs)[1, 4, 9, 16, 25, 36, 49, 64, 81]

Kesako ?

λ ?

Pas vraiment ...

Page 6: Programmation fonctionnelle

Kesako ?

« La programmation fonctionnelle est un style de programmation qui met l'accent sur l'évaluation d’expressions, plutôt que sur l'exécution de commandes. »

Graham Hutton

Page 7: Programmation fonctionnelle

Kesako ?

Les programmes impératifs sont des séquences d’instructions

void estPair(int x){ if (x % 2 == 0) printf("x est pair !\n"); else printf("x est impair !\n");}Te

mps Fais ça

puis çapuis ça...

Page 8: Programmation fonctionnelle

Kesako ?

La programmation fonctionnelle retire cette notion de temps.

Page 9: Programmation fonctionnelle

“The world's most popular functional language”

Page 10: Programmation fonctionnelle

Kesako ?

Comment ?

Une fonction ou une expression accepte des données en entrée et en retourne de nouvelles.

Mais ne modifie aucun état global, ni aucun de ses arguments.

Page 11: Programmation fonctionnelle

Kesako ?

Comment ?● Pas de modification des données

○ Pour modifier une donnée, on en crée une nouvelle copie

● Pas d’effet de bord○ Pas de modification de variables globales○ Pas d’entrée/sortie

Page 12: Programmation fonctionnelle

Kesako ?

struct rect_t { int x, y, width, height;}

void move(rect_t *rect, int dx, int dy){ rect->x += dx; rect->y += dy;}

struct rect_t { int x, y, width, height;}

rect_t move(rect_t rect, int dx, int dy){ return { .x = rect.x + dx, .y = rect.y + dy, .width = rect.width, .height = rect.height };}

Impératif Fonctionnel

Page 13: Programmation fonctionnelle

Kesako ?

rect_t my_rectangle(){ rect_t rect = { .x = 0, .y = 0, .width = 100, .height = 100 };

move(&rect, 10, 10);

return rect;}

rect_t my_rectangle(){ rect_t rect = { .x = 0, .y = 0, .width = 100, .height = 100 };

return move(rect, 10, 10);}

Impératif Fonctionnel

Page 14: Programmation fonctionnelle

Kesako ?

● Les fonctions sont :○ déterministes○ plus facilement testables○ thread-safes○ plus modulables○ plus réutilisables

● Code plus facilement lisible● Moins d’erreurs● Optimisations

● Performances○ Mais pas toujours ...

● Pas d’entrées/sorties

Avantages Désavantages

Page 15: Programmation fonctionnelle

Récursion

?

Impératif Fonctionnelint sum_n(int n){ int sum = 0; for (int i = 1; i <= n; i++) sum += i;

return sum;} Modification de variable

Page 16: Programmation fonctionnelle

Récursion

int sum_n(int n){ int sum = 0; for (int i = 1; i <= n; i++) sum += i;

return sum;}

int sum_n(int n){ if (n <= 0) return 0; else return n + sum_n(n - 1);}

Impératif Fonctionnelint sum_n(int n){ int sum = 0; for (int i = 1; i <= n; i++) sum += i;

return sum;} Modification de variable

Page 17: Programmation fonctionnelle

Plan

● Kesako ?● Haskell

○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin

Page 18: Programmation fonctionnelle

Haskell - Syntaxe

-- Tous les opérateurs sont des fonctions(+) :: Int -> Int -> Int

-- Les fonctions sont des valeursadd :: Int -> Int -> Intadd = +

-- Une fonction a 2 arguments est une -- fonction à 1 argument qui retourne-- une fonction à 1 argument !next :: Int -> Intnext = add 1-- Ou directementnext = + 1

two = next 1 -- Equivalent à “add 1 1”

pi :: Doublepi = 3.1416

square :: Int -> Intsquare x = x * x

-- Pas de parenthèse pour les appels de-- fonctionsfour :: Intfour = square 2

-- Pattern matchingisFive 5 = TrueisFive x = False

-- RécursionsumN n = if n <= 0 then 0 else n + sumN (n - 1)

Page 19: Programmation fonctionnelle

Haskell - Listes

-- Liste videempty :: [Int]empty = []

-- ":" permet d'ajouter un élément au début de la liste(:) :: Int -> [Int] -> [Int]

one :: [Int]one = 1 : empty

xs :: [Int]xs = 1 : 2 : 3 : 4 : 5 : []-- Equivalent à :xs = [ 1, 2, 3, 4, 5 ]

-- Pattern matching sur ":" et "[]"

length :: [Int] -> Int

length [] = 0

length (y : ys) = 1 + length ys

-- Concaténation de deux listes avec "++"

(++) :: [Int] -> [Int] -> [Int]

[] ++ zs = zs

(y : ys) ++ zs = y : (ys ++ zs)

-- Donne les premiers éléments d'une liste

take n [] = []

take 0 ys = []

take n (y : ys) = y : take (n - 1) ys

xs = : 1 2: 3: 4: 5: []

Page 20: Programmation fonctionnelle

Plan

● Kesako ?● Haskell

○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin

Page 21: Programmation fonctionnelle

Stuff - Higher-order functions

-- Les fonctions peuvent elles-mêmes-- recevoir des fonctions en argument :map :: (Int -> Int) -> [Int] -> [Int]map f [] = []map f (x : xs) = f x : map f xs

filter :: (Int -> Bool) -> [Int] -> [Int]filter p [] = []filter p (x : xs) = if p x then x : filter p xs else filter p xs

>>> map square [ 1, 2, 3, 4, 5 ]

[ 1, 4, 9, 16, 25 ]

>>> filter (> 3) [ 10, 2, 3, 5, 0, 7 ]

[ 10, 5, 7 ]

Page 22: Programmation fonctionnelle

Stuff - Quick Sort !

qsort [ 5, 2, 3, 10, 0, 7 ]

qsort [ 2, 3, 0 ] ++ [ 5 ] ++ qsort [ 7, 10 ]

qsort [ 0 ] ++ [ 2 ] ++ qsort [ 3 ] qsort [] ++ [ 7 ] ++ qsort [ 10 ]

[] ++ [ 0 ] ++ [] [] ++ [ 3 ] ++ [] [] ++ [ 10 ] ++ []

Page 23: Programmation fonctionnelle

qsort [ 5, 2, 3, 10, 0, 7 ]

qsort [ 2, 3, 0 ] ++ [ 5 ] ++ qsort [ 7, 10 ]

qsort [ 0 ] ++ [ 2 ] ++ qsort [ 3 ] qsort [] ++ [ 5 ] ++ qsort [ 10 ]

[] ++ [ 0 ] ++ [] [] ++ [ 3 ] ++ [] [] ++ [ 10 ] ++ []

Stuff - Quick Sort !

qsort :: [Int] -> [Int]

qsort [] = []

qsort (x : xs) = qsort lesser ++ [ x ] ++ qsort greater

where

lesser = filter (<= x) xs

greater = filter (> x) xs

Page 24: Programmation fonctionnelle

Stuff - Quick Sort !

>>> qsort oneMillion

5.05 secs

Page 25: Programmation fonctionnelle

Stuff - Quick Sort !

>>> qsort oneMillion

5.05 secs

>>> take 100 (qsort oneMillion)

Page 26: Programmation fonctionnelle

Stuff - Haskell is lazy

>>> qsort oneMillion

5.05 secs

>>> take 100 (qsort oneMillion)

0.48 secs

WTF ?!!?

Page 27: Programmation fonctionnelle

Stuff - Haskell is lazy

● Haskell est un langage à évaluation « paresseuse »○ Une donnée calculée que lorsqu’elle est accèdée pour

la première fois● Chaque noeud d’une liste est une donnée : 1 2: []

Page 28: Programmation fonctionnelle

Stuff - Haskell is lazy

take 3 (qsort [ 5, 2, 3, 10, 0, 7 ])

qsort [ 2, 3, 0 ] ++ [ 5 ] ++ qsort [ 7, 10 ]

qsort [ 0 ] ++ [ 2 ] ++ qsort [ 3 ] qsort [] ++ [ 5 ] ++ qsort [ 10 ]

[] ++ [ 0 ] ++ [] [] ++ [ 3 ] ++ [] [] ++ [ 10 ] ++ []

● Haskell est un langage à évaluation « paresseuse »○ Une donnée calculée que lorsqu’elle est accèdée pour

la première fois● Chaque noeud d’une liste est une donnée : 1 2: []

Page 29: Programmation fonctionnelle

Plan

● Kesako ?● Haskell

○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin

Page 30: Programmation fonctionnelle

Real world stuff - Entrées sorties

IO

Fonctionnel

Page 31: Programmation fonctionnelle

Real world stuff - Entrées et sorties

-- Les fonctions ayant des effets de bords retournent “ IO a ”,-- où “ a ” est la valeur retournée.-- “ () ” est l'équivalent de “ void ”.

putStrLn :: Text -> IO ()

readFile :: FilePath -> IO Text

writeFile :: FilePath -> Text -> IO ()

getArgs :: IO [Text]

Page 32: Programmation fonctionnelle

Real world stuff - Entrées et sorties

-- “ do ” permet de séquencer des fonctions à effets de bord-- comme dans un langage impératif.-- “ <- ” permet de récupérer le résutat d’une “ IO ”.

main :: IO ()main = do [ path ] <- getArgs c <- readFile path putStrLn c

Page 33: Programmation fonctionnelle

Real world stuff - Grep

$ grep "Maître" le_corbeau_et_le_renard.txt

Maître Corbeau, sur un arbre perché,

Maître Renard, par l’odeur alléché,

Page 34: Programmation fonctionnelle

Real world stuff - Grep

lines :: Text -> [Text]unlines :: [Text] -> TextisInfixOf :: Text -> Text -> Bool

grep :: Text -> Text -> Textgrep pattern text = unlines matches where ls = lines text matches = filter (isInfixOf pattern) ls

main = do [pattern, path] <- getArgs text <- readFile path putStrLn (grep pattern text)

Page 35: Programmation fonctionnelle

Real world stuff - Grep

$ du -h de_bello_gallico.txt

144K de_bello_gallico.txt

$ grep "Belg" de_bello_gallico.txt

[ 26 lignes ... ]

0.003 secs (1 868 870 cycles CPU)

$ ./GrepHS "Belg" de_bello_gallico.txt

[ 26 lignes ... ]

0.008 secs (6 603 153 cycles CPU, GC : 1.4%) - Mem. max. : 1 MB

Page 36: Programmation fonctionnelle

Real world stuff - Grep

$ du -h de_bello_gallico_large.txt

141M de_bello_gallico_large.txt

$ grep "Belg" de_bello_gallico_large.txt

[ 26 000 lignes ... ]

0.0988 secs (326 516 484 cycles CPU)

$ ./GrepHS "Belg" de_bello_gallico_large.txt

[ 26 000 lignes ... ]

1.632 secs (5 973 858 671 cycles CPU, GC : 0.5 %) - Mem. max. : 1 MB

Page 37: Programmation fonctionnelle

Real world stuff - Haskell lazy again !

$ du -h de_bello_gallico_large.txt

141M de_bello_gallico_large.txt

$ grep "Belg" de_bello_gallico_large.txt

[ 26 000 lignes ... ]

0.0988 secs (326 516 484 cycles CPU)

$ ./GrepHS "Belg" de_bello_gallico_large.txt

[ 26 000 lignes ... ]

1.632 secs (5 973 858 671 cycles CPU, GC : 0.5 %) - Mem. max. : 1 MB

WTF ?!!??

text <- readFile pathputStrLn (grep pattern text)

Page 38: Programmation fonctionnelle

Real world stuff - Haskell lazy again !

text =

[]

: alléché\nLui tint à peu près ce langage :\n"Hé ! bonjour, Monsieur du Corbeau.\nQue vous êtes joli

: êtes le Phenix des hôtes de ces bois.\nÀ ces mots le Corbeau ne se sent pas de joie :\nEt pour montrer

: ! que vous me semblez beau !\nSans mentir, si votre ramage\nSe rapporte à votre plumage,\nVous

: sa belle voix,\nIl ouvre un large bec, laisse tomber sa proie.\nLe Renard s’en saisit, et dit : Mon bon

: un fromage sans doute.\nLe Corbeau honteux et confus\nJura, qu’on ne l’y prendrait plus.

: Monsieur,\nApprenez que tout flatteur\nVit aux dépens de celui qui l’écoute.\nCette leçon vaut bien

Maître Corbeau sur un arbre perché,\nTenait en son bec un fromage.\nMaître Renard par l’odeur:

Page 39: Programmation fonctionnelle

Plan

● Kesako ?● Haskell

○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin

Page 40: Programmation fonctionnelle

Aller plus loin - Pourquoi ?

● Programmer ...○ … plus modulable○ … plus réutilisable○ … plus rigoureusement

● Monstrueusement efficace pour ...○ … la programmation parallèle et concurrente○ … le backend et les réseaux

● De plus en plus de langages tendent vers le paradigme

Page 41: Programmation fonctionnelle

Aller plus loin - Langages

Fonctionnel

Orienté objet Impéra

tif

LISPs

Page 42: Programmation fonctionnelle

Aller plus loin - Langages

Fonctionnel

Orienté objet Impéra

tif

LISPs

Microsoft .NET

Java VM

Réseaux et haute disponibilité

Très bas niveau

Page 43: Programmation fonctionnelle

Aller plus loin - Langages

Fonctionnel

Orienté objet Impéra

tif

LISPs

Page 44: Programmation fonctionnelle
Page 45: Programmation fonctionnelle

Moyenne sur 13 benchmarksSource : http://benchmarksgame.alioth.debian.org/u64q/which-programs-are-fastest.html

Page 46: Programmation fonctionnelle

Benchmark des context-switchs.Source : http://benchmarksgame.alioth.debian.org/u64q/performance.php?test=threadring