7. @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
10. @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
13. @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
18. @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!
19. @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)!
23. @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!
24. @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!
26. @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!
27. @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
28. @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!
29. @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!
33. @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);!
}!
};!
34. @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);!
35. @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!
36. @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)
37. @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
38. @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