Programmation fonctionnelle
Transcript of Programmation fonctionnelle
La programmation fonctionnelleEn 45 minutes
Raphael Javaux
Plan
● Kesako ?● Haskell
○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin
Plan
● Kesako ?● Haskell
○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin
>>> 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 ?
λ ?
>>> 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 ...
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
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...
Kesako ?
La programmation fonctionnelle retire cette notion de temps.
“The world's most popular functional language”
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.
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
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
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
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
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
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
Plan
● Kesako ?● Haskell
○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin
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)
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: []
Plan
● Kesako ?● Haskell
○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin
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 ]
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 ] ++ []
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
Stuff - Quick Sort !
>>> qsort oneMillion
5.05 secs
Stuff - Quick Sort !
>>> qsort oneMillion
5.05 secs
>>> take 100 (qsort oneMillion)
Stuff - Haskell is lazy
>>> qsort oneMillion
5.05 secs
>>> take 100 (qsort oneMillion)
0.48 secs
WTF ?!!?
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: []
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: []
Plan
● Kesako ?● Haskell
○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin
Real world stuff - Entrées sorties
IO
Fonctionnel
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]
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
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é,
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)
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
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
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)
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:
Plan
● Kesako ?● Haskell
○ “An advanced purely-functional programming language”● Stuff● Real world stuff● Aller plus loin
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
Aller plus loin - Langages
Fonctionnel
Orienté objet Impéra
tif
LISPs
Aller plus loin - Langages
Fonctionnel
Orienté objet Impéra
tif
LISPs
Microsoft .NET
Java VM
Réseaux et haute disponibilité
Très bas niveau
Aller plus loin - Langages
Fonctionnel
Orienté objet Impéra
tif
LISPs
Moyenne sur 13 benchmarksSource : http://benchmarksgame.alioth.debian.org/u64q/which-programs-are-fastest.html
Benchmark des context-switchs.Source : http://benchmarksgame.alioth.debian.org/u64q/performance.php?test=threadring