WTF - What's The Fold - Bordeaux JUG 2013

1,448 views

Published on

Venez découvrir le concept de Fold !
Hérité de la programmation fonctionnelle, le Fold abstrait l'itération sur vos structures de données, et améliore l'expressivité de votre code.
Avec de vrais bouts de Java 8 et une pincée de Haskell !

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,448
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

WTF - What's The Fold - Bordeaux JUG 2013

  1. 1. WTF ? (What's the Fold) principes de programmation fonctionnelle, expliqués simplement Olivier Croisier
  2. 2. SPEAKER Olivier Croisier JavaSpecialist™ Consultant @Zenika Formateur Speaker Blogger TheCodersBreakfast.net @OlivierCroisier olivier@thecodersbreakfast.net github.com/OlivierCroisier
  3. 3. FOLD ? Programmation fonctionnelle Haskell, Scala... ? Difficile ? Vocabulaire Functor, Applicative, Monoid, Monad, Arrow... map(), filter()... fold()
  4. 4. FOLD ? Définition en Haskell foldl :: (a → b → a) → a → [b] → a … Pas de panique !
  5. 5. FOLD ? Exercice 1 Soit une liste d'entiers → Les additionner List<Integer> nums = Arrays.asList(1,2,3,4,5);
  6. 6. FOLD ? Exercice 1 Soit une liste d'entiers → Les additionner List<Integer> nums = Arrays.asList(1,2,3,4,5); public Integer sum(List<Integer> nums) { Integer sum = 0; for (Integer num : nums) { sum = sum + num; } return sum; }
  7. 7. FOLD ? Exercice 2 Soit une liste d'entiers → Les multiplier List<Integer> nums = Arrays.asList(1,2,3,4,5);
  8. 8. FOLD ? Exercice 2 Soit une liste d'entiers → Les multiplier List<Integer> nums = Arrays.asList(1,2,3,4,5); public Integer product(List<Integer> nums) { Integer product = 1; for (Integer num : nums) { product = product * num; } return product; }
  9. 9. FOLD ? Pattern commun Accumulateur ← valeur initiale Boucle sur la liste Opération (accumulateur, élément) public Integer foo(List<Integer> nums) { Integer accu = <init>; for (Integer num : nums) { accu = accu <op> num; } return accu; }
  10. 10. FOLD ? Type de l'accumulateur Type des éléments de la liste public <A, E> A fold (BiFunction<A, E, A> op, A init, List<E> list) { A accu = init; for (E num : list) { accu = op.apply(accu, num); } return accu; }
  11. 11. FOLD ? BiFunction<Integer,Integer,Integer> plus = new BiFunction<>() { public Integer apply(Integer accu, Integer elem) { return accu + elem; } }; BiFunction<Integer,Integer,Integer> mult = new BiFunction<>() { public Integer apply(Integer accu, Integer elem) { return accu * elem; } }; Integer sum = fold (plus, 0, nums); Integer product = fold (mult, 1, nums);
  12. 12. FOLD ? Java 8 : Expressions Lambda (args) -> expression BiFunction<Int,Int,Int> BiFunction<Int,Int,Int> plus mult = = (a,e) (a,e) Integer Integer sum product = = fold fold (plus, (mult, 0, 1, Integer Integer sum product = = fold fold ((a,e)->a+e, ((a,e)->a*e, -> -> a+e; a*e; nums); nums); 0, 1, nums); nums);
  13. 13. FOLD ? Java 8 : Références de méthodes Class::staticFunction Integer sum = fold (Integer::plus, 0, nums); public class MathUtil { public static Integer mult(Integer x,Integer y) { return x * y; } } Integer prod = fold (MathUtil::mult, 1, nums);
  14. 14. FOLD ? Définition en Haskell foldl :: (a → b → a) → a → [b] → a fonction (a,b) → a accumulateur de type a résultat liste<b>
  15. 15. PRINCIPES Définition “ En programmation fonctionnelle, l'opération fold (ou reduce) est une famille de fonctions d'ordre supérieur qui traitent une structure de données dans un certain ordre pour produire un résultat. – http://www.haskell.org/haskellwiki/Fold
  16. 16. PRINCIPES Avantages Mécanisme très générique Fonction d'ordre supérieur Encapsulation de l'itération Expressivité ("quoi" vs "comment") Optimisation des opérations associatives Famille de fonctions foldl, foldr, foldl1, foldr1 scanl, scanr, scanl1, scanr1
  17. 17. PRINCIPES Fold left - foldl accumulateur 0 + 1 [1,2,3,4,5] 1 + 2 [1,2,3,4,5] 3 + 3 [1,2,3,4,5] 6 + 4 10 + 5 15 [1,2,3,4,5] [1,2,3,4,5]
  18. 18. PRINCIPES Fold right - foldr itération inversée ! accumulateur [1,2,3,4,5] 5 + 0 [1,2,3,4,5] 4 + 5 [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] 3 + 9 2 + 12 1 + 14 15
  19. 19. PRINCIPES Fold left vs Fold right Opérations non commutatives (soustraction, division...) foldl foldr (-) (-) 0 0 [1..5] [1..5] quiz ! Performances Plus efficace d'ajouter en tête des listes → foldr : élément à gauche, liste à droite
  20. 20. PRINCIPES Autres folds foldl1, foldr1 Même principe que foldl et foldr Accumulateur ← 1° élément de la liste foldl (+) 0 [1..5] foldl1 (+) X [1..5] valeur initiale implicite
  21. 21. PRINCIPES Autres folds scanl, scanr scanl1, scanr1 Même principe Renvoient toutes les valeurs intermédiaires scanl (+) 0 [1..5] [0,1,3,6,10,15] scanr (+) 0 [1..5] [15,14,12,9,5,0]
  22. 22. USAGES Folds complexes Fold sert de base à beaucoup d'algorithmes impliquant le parcours d'une liste Le résultat peut être une valeur unique ("reduce") ou une autre liste ! Dépend de l'accumulateur et de l'opération On peut effectuer une opération complexe par composition de fonctions simples f(g(x)) ↔ (f ⋅ g)(x)
  23. 23. USAGES Fonction map Applique une fonction f à chaque élément [1,2,3,4,5] → [f(1),f(2),f(3),f(4),f(5)] Implémentation avec foldr Accumulateur ← liste cible vide Pour chaque élément e : - Calculer f(e) - Ajouter f(e) à la liste cible fonction composée
  24. 24. USAGES Fonction map "cons" fonction f result = foldr ((:).(*2)) [] [1..5] composition de fonctions - application de f - puis ajout à la liste
  25. 25. USAGES Fonction map List<Integer> accu = new ArrayList<>(); BiFunction<List<Integer>,Integer,List<Integer>> op = (l,e) -> { l.add(0, e * 2); return l; }; List<Int> result = foldr(op, accu, nums);
  26. 26. USAGES Fonction filter Sélectionne uniquement les éléments qui répondent à un prédicat p [1,2,3,4,5] –-(garder si >3)--> [4,5] Implémentation avec foldr Accumulateur ← liste cible vide Pour chaque élément e : - Vérifier p(e) - Si p(e), ajouter e à la liste cible fonction composée
  27. 27. USAGES Fonction filter ajout de l'élément à l'accumulateur let op e list = if e then else > 3 (e:list) list result = foldr op [] [1..5]
  28. 28. USAGES Fonction filter List<Integer> accu = new LinkedList<>(); BiFunction<List<Integer>,Integer,List<Integer>> op = (l, e) -> { if (e > 3) l.add(0,e); return l; }; List<Int> result = foldr(op, accu, nums);
  29. 29. USAGES Fonction count Compte le nombre d'éléments dans la liste [1,2,3,4,5] → 5 Implémentation avec foldl Accumulateur ← 0 Pour chaque élément e : - Incrémenter l'accumulateur
  30. 30. USAGES Fonction count count = foldl (a e → a+1) 0 [1..5] Integer result = foldl((a,e)->a+1, 0, nums)
  31. 31. USAGES Fonction max Renvoie le plus grand élément de la liste [1,2,3,4,5] → 5 Implémentation avec foldl Accumulateur ← 0 Pour chaque élément e : - Si e > accumulateur, alors accumulateur = e
  32. 32. USAGES Fonction max let op e m = if e then else > m e m result = foldl op 0 [1..5] Integer max = foldl((e,m)-> e>m?e:m, 0, nums);
  33. 33. IMPLEMENTATIONS Java 8 Notion de Stream (java.util.stream.Stream) Pipeline de transformation Spécialisé par type (IntStream…) Implémente reduce (foldl restreint à 1 type) T reduce( T identity, BinaryOperator<T> reducer ); List<Integer> nums = Arrays.asList(1,2,3,4,5); int sum = nums.stream() .reduce(0, Integer::sum);
  34. 34. IMPLEMENTATIONS Javascript Sur les tableaux reduce (foldl) et reduceRight (foldr) array.reduce (func, array.reduceRight(func, initval) initval) var nums = new Array(1,2,3,4,5); var sum = nums.reduce( function(a,e) {return a+e;}, 0);
  35. 35. IMPLEMENTATIONS Scala Sur les listes et tableaux foldLeft (/:) et foldRight (:) List.foldLeft (initval)(func) List.foldRight(initval)(func) val nums = Array(1, 2, 3, 4, 5) val sum = nums.foldLeft(0)(_+_) val sum = (0 /: list)(_+_)
  36. 36. IMPLEMENTATIONS Groovy Sur les listes list.inject (foldl) nums = [1,2,3,4]; sum = nums.inject(0) { a,e -> a+e }
  37. 37. CONCLUSION Alors, What's The Fold ? Un principe simple, puissant et générique Socle pour d'autre opérations map, filter, count... Déjà présent dans vos langages reduce, inject, foldLeft... Apprenez à le reconnaître !
  38. 38. questions ?

×