@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 ?

Devoxx France 2014 - La puissance de mon Monoïde est supérieure à 9000