Upload
xebia-france
View
1.187
Download
2
Embed Size (px)
Citation preview
@benoit_lemoine #monoid9000
La puissance de mon monoïde est supérieure à 9000
@benoit_lemoine Xebia Développeur
@benoit_lemoine #monoid9000
Qu’est ce qu’un monoïde ?
Un monoïde est un magma unifère associatif
Non, en vrai, c’est quoi un monoïde ?
@benoit_lemoine #monoid9000
TypeScript • Syntaxe proche de JavaScript • Sucre syntaxique et classe • Typage statique • Langage cool
@benoit_lemoine #monoid9000
Il était une fois…
@benoit_lemoine #monoid9000
class Guy { ! constructor(public power:number) {} !! //Égalité structurelle ! equals(g:Guy): boolean { ! return g.power == this.power! } ! } !! var boo = new Guy(8500) ! console.log(boo.power) //affiche 8500 !
Modélisons Boo
@benoit_lemoine #monoid9000
Mais la Terre est fournie avec son protecteur
@benoit_lemoine #monoid9000
var boo = new Guy(8500); ! var goku = new Guy(4000); !! function fight(guy1:Guy, guy2:Guy):Guy { ! return guy1.power > guy2.power ? guy1 : guy2; ! }; !! var winner = fight(goku, boo); ! console.log(winner); ! // affiche boo, car il est de loin le plus fort !!
Modélisons Goku et le combat
@benoit_lemoine #monoid9000
Goku a perdu !
@benoit_lemoine #monoid9000
Appel à un ami !
@benoit_lemoine #monoid9000
var boo = new Guy(8500); !var goku = new Guy(4000); !var vegeta = new Guy(3900); !!function fusion(guy1:Guy, guy2:Guy):Guy { ! return new Guy(guy1.power + guy2.power); !} !!var bejito = fusion(goku, vegeta); // puissance de 7900 !!var winner = fight(bejito, boo) !console.log(winner) !// affiche toujours boo, car il est toujours le plus fort !
Modélisons la fusion
@benoit_lemoine #monoid9000
Bejito est vaincu !
@benoit_lemoine #monoid9000
Augmentation du nombre de ressources
@benoit_lemoine #monoid9000
var goten = new Guy(2000); ! var trunks = new Guy(2500); !! var gotenks = fusion(goten, trunks); // puissance de 4500 ! var gobejitenks = fusion(gotenks, bejito); // puissance de 12400 !! fight(gobejitenks, boo); // gobejitenks gagne !
Fusion partout
@benoit_lemoine #monoid9000
La victoire était assurée car
@benoit_lemoine #monoid9000
function fusion(guy1:Guy, guy2:Guy):Guy { ! return new Guy(guy1.power + guy2.power); ! } !
Loi de composition interne
fusion est une fonction… • …qui prend 2 paramètres du même type Guy !• …qui renvoie une valeur du même type Guy !
@benoit_lemoine #monoid9000
function fusion(guy1:Guy, guy2:Guy):Guy { ! return new Guy(guy1.power + guy2.power); ! } !! var fusionned1 = fusion(fusion(goku, vegeta), goten); ! var fusionned2 = fusion(goku, fusion(vegeta, goten)); !! console.log(fusionned1.equals(fusionned2)); //affiche true!
Associativité
@benoit_lemoine #monoid9000
var gobejitenks = [goku, vegeta, goten, trunks].reduce(fusion) !
Loi de composition interne associative
Rend plus lisible les fold/inject/reduce!
@benoit_lemoine #monoid9000
var goku = new Guy(4000); ! var mrSatan = new Guy(0); !! var gotan = fusion(goku, mrSatan); ! var saku = fusion(mrSatan, goku); !! console.log(gotan.equals(saku)) //affiche true! console.log(gotan.equals(goku)) //affiche true! console.log(saku.equals(goku)) //affiche true!
Élément neutre de fusion!
@benoit_lemoine #monoid9000
On a un monoïde ! Un monoïde est un ensemble muni d’une loi de composition interne associative et d’un élément neutre • Ensemble des Guy !• fusion !• new Guy(0) !
@benoit_lemoine #monoid9000
ET ?
À quoi ça sert ?
@benoit_lemoine #monoid9000
La fusion, ça prend du temps
@benoit_lemoine #monoid9000
Q, Librairie de promesses • Exécution séquentielle de code asynchrone • Composabilité • Les promesses, c’est cool
@benoit_lemoine #monoid9000
//La fusion éxecutera la callback de promesse après 0.5 seconde ! function fusion(guy1:Guy,guy2:Guy):Q.IPromise<Guy> { ! var deferred = Q.defer(); !! setTimeout(function() { ! deferred.resolve(new Guy(guy1.power + guy2.power)) ! }, 500); !! return deferred.promise; ! }; !!
fusion différée !
@benoit_lemoine #monoid9000
var boo = new Guy(8500); ! var goku = new Guy(4000); ! var vegeta = new Guy(3500); !! var promiseForBejito:Q.IPromise<Guy> = fusion(goku, vegeta); !! promiseForBejito.done(function(bejito:Guy) { ! // affiche boo, une fois que la fusion est finie ! console.log(fight(bejito, boo)); ! }); !
Exemple !
@benoit_lemoine #monoid9000
fusion n’est plus une loi de composition interne
Le type de retour Q.IPromise<Guy> n'est pas le même que celui d'entrée, Guy !
@benoit_lemoine #monoid9000
function fusionPromise(guy1:Q.IPromise<Guy>, ! guy2:Q.IPromise<Guy>):Q.IPromise<Guy> { ! return Q.all([guy1, guy2]).then((guys) => fusion(guys[0], guys[1])) ! } !! var noHero:Q.IPromise<Guy> = Q(new Guy(0)); ! var heroes = [goku, vegeta, goten, trunks]; ! var promiseForHeroes:Array<Q.IPromise<Guy>> = heroes.map(Q); ! var promiseForGobejitenks = promiseForHeroes.reduce(fusionPromise, noHero); !! promiseForGobejitenks.done((gobejitenks) => { ! // gobejitenks gagne, après 1.5 secondes ! console.log(fight(gobejitenks, boo)) ! }); !
Retour de la loi de composition interne !
@benoit_lemoine #monoid9000
Algorithme de parcours en arbre
Si la liste contient Alors…
0 élément … on renvoie l’élément neutre
1 élément … on renvoie l’élément de la liste
2 éléments … on renvoie la fusion des deux élements
Plus de 2 éléments … on divise la liste en 2 parts et on exécute l'algorithme ici défini sur chacune des parties, avant de fusionner leurs résultats
@benoit_lemoine #monoid9000
function reduceFusion(coll:Array<Q.IPromise<Guy>>):Q.IPromise<Guy> { ! var elementsCount = coll.length; ! if(elementsCount == 2) { ! return fusionPromise(coll[0], coll[1]); ! } else if(elementsCount == 1) { ! return fusionPromise[0]; ! } else if (elementsCount == 0) { ! return Q(new Guy(0)) ! } else { ! var halfSize = elementsCount / 2 ! var half1Combined = reduceFusion(coll.slice(0, halfSize)); ! var half2Combined = reduceFusion(coll.slice(halfSize, elementsCount)); ! return fusionPromise(half1Combined, half2Combined); ! } ! }; !
Attention, fonction récursive à l’horizon!
@benoit_lemoine #monoid9000
var promiseForHeroes = [goku, vegeta, goten, trunks].map(Q) ! reduceFusion(promiseForHeroes).done(function(gobejitenks) { ! //gobejitenks gagne, après seulement 1s, et plus 1.5 s ! console.log(fight(gobejitenks, boo)); ! }); !
Usage !
@benoit_lemoine #monoid9000
Optimisation sous forme de parcours d’arbre
@benoit_lemoine #monoid9000
Que fallait-il pour paralléliser ?
Une loi de composition interne… • …associative • …avec un élément neutre
Un monoïde !
@benoit_lemoine #monoid9000
Abstraction de monoïde!
interface Monoid<T> { ! ZERO:T; //element neutre ! combine:(a:T, b:T) => T //loi de composition interne ! } !
@benoit_lemoine #monoid9000
Reduce, parallèlisation et monoïde !
var reduceMonoid = function<T>(m:Monoid<T>, coll:Array<T>):T { ! var elementsCount = coll.length; ! if(elementsCount == 2) { ! return m.combine(coll[0], coll[1]); ! } else if(elementsCount == 1) { ! return coll[0]; ! } else if (elementsCount == 0) { ! return m.ZERO! } else { ! var halfSize = elementsCount / 2 ! var firstHalf = reduceMonoid(m, coll.slice(0, halfSize)); ! var secondHalf = reduceMonoid(m, coll.slice(halfSize, elementsCount)); ! return m.combine(firstHalf, secondHalf); ! } ! }; !
@benoit_lemoine #monoid9000
Fusion et Reduce Monoïde !
var monoidOfPromiseOfGuy:Monoid<Q.IPromise<Guy>> = { ! ZERO: Q(new Guy(0)), ! combine: fusionPromise! }; !! var promiseForHeroes = [goku,vegeta, goten, trunks].map(Q) ! var promiseForGobejitenks = ! reduceMonoid(monoidOfPromiseOfGuy, promiseForHeroes); !
@benoit_lemoine #monoid9000
Quand on commence à penser monoïde!
var monoidOfBetterGuy: Monoid<Guy> = { ! ZERO:new Guy(0), ! combine:fight! }; ! var heroes = [goku,vegeta, boo, goten, trunks]; ! var winnerOfBattleRoyale = ! reduceMonoid(monoidOfBetterGuy, heroes); // renvoit boo!
On en voit partout!
@benoit_lemoine #monoid9000
Au fond, les monoïdes sont partout Quelques exemples :
(ensemble, opération, élément neutre)
• (number, +, 0) • (number, *, 1) • (number > 0, max, 0) • (string, '', +) • (array, [], concat)
@benoit_lemoine #monoid9000
En résumé – Le monoïde
• Améliore la lisibilité • Permet le parcours de liste comme un arbre • Permet la parallélisation des traitements
@benoit_lemoine #monoid9000
En résumé – Les mathématiques
Les gros mots des matheux couvrent des abstractions… • … abstractions qui permettent la réutilisabilité d’un
concept • … abstractions qui imposent un « contrat » aux
ensembles auxquels elles s’appliquent, comme nos interfaces
@benoit_lemoine #monoid9000
Des questions ?