Slide 1

Slide 1 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Programmation fonctionnelle en JavaScript Philippe Charrière ! @k33g @k33g_org ! https://github.com/k33g/q/issues GitHub

Slide 2

Slide 2 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Pourquoi ce talk?

Slide 3

Slide 3 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 4

Slide 4 text

#voxxeddaysLU voxxeddays.com/luxembourg/ http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html

Slide 5

Slide 5 text

#voxxeddaysLU voxxeddays.com/luxembourg/ http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html

Slide 6

Slide 6 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Précautions d’usage

Slide 7

Slide 7 text

#voxxeddaysLU voxxeddays.com/luxembourg/ sondage

Slide 8

Slide 8 text

#voxxeddaysLU voxxeddays.com/luxembourg/ > vocabulaire(s) > implémentations incomplètes > échanges de points de vue: https:/ /github.com/k33g/voxxed.lu.functional.js/issues

Slide 9

Slide 9 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Programmation fonctionnelle?

Slide 10

Slide 10 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Définition > Coder avec uniquement des fonctions pures > = fonctions sans “side effect” > toujours retourner le même résultat pour les mêmes entrées > ne pas modifier de variable > ne pas propager d’exception ou s’arrêter lors d’une erreur > pas de print, pas de input > pas de lecture / écriture de fichier > … développeurs fonctionnels

Slide 11

Slide 11 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Nous allons voir > Rapidement: currying > Container > Functor > Monad > Maybe > Either > Validation ⚠

Slide 12

Slide 12 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Prog. Fonctionnelle 1 truc utile avant de commencer

Slide 13

Slide 13 text

#voxxeddaysLU voxxeddays.com/luxembourg/ “currying”

Slide 14

Slide 14 text

#voxxeddaysLU voxxeddays.com/luxembourg/ let addition = function(a,b) {
 return a+b;
 };
 
 // currying addition
 let add = function(a) {
 return function(b) {
 return a + b;
 }
 }; “The concept is simple: You can call a function with fewer arguments than it expects. It returns a function that takes the remaining arguments.” - Brian Lonsdorf

Slide 15

Slide 15 text

#voxxeddaysLU voxxeddays.com/luxembourg/ add(40)(2)
 
 incrementBy1 = add(1)
 
 incrementBy1(41)
 
 let arr1 = [100, 200, 300, 400, 500];
 
 arr1.map((x)=>{ return x + 1 })
 
 arr1.map(incrementBy1)

Slide 16

Slide 16 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Container

Slide 17

Slide 17 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 18

Slide 18 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Container {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 static of(x) { // a constructor
 return new Container(x);
 }
 }

Slide 19

Slide 19 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 20

Slide 20 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Functor

Slide 21

Slide 21 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 22

Slide 22 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 23

Slide 23 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 24

Slide 24 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 25

Slide 25 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 26

Slide 26 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Functor {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value }) 
 }
 
 static of(x) {
 return new Functor(x);
 }
 
 map (fn) {
 return Functor.of(fn(this.value));
 }

Slide 27

Slide 27 text

#voxxeddaysLU voxxeddays.com/luxembourg/ map(function) I’m a Functor!

Slide 28

Slide 28 text

#voxxeddaysLU voxxeddays.com/luxembourg/ DEMO?

Slide 29

Slide 29 text

#voxxeddaysLU voxxeddays.com/luxembourg/ 42 Appliquer un ensemble de traitements addOne = (value) => value + 1;
 multiplyBy5 = (value) => value * 5;
 divideByThree = (value) => value / 3;
 
 a = Functor.of(23.2);
 
 b = a
 .map(addOne)
 .map(addOne)
 .map(multiplyBy5)
 .map(divideByThree);

Slide 30

Slide 30 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Monad

Slide 31

Slide 31 text

#voxxeddaysLU voxxeddays.com/luxembourg/ map(function)

Slide 32

Slide 32 text

#voxxeddaysLU voxxeddays.com/luxembourg/ functor map(function)

Slide 33

Slide 33 text

#voxxeddaysLU voxxeddays.com/luxembourg/ DEMO?

Slide 34

Slide 34 text

#voxxeddaysLU voxxeddays.com/luxembourg/ “aplatir”

Slide 35

Slide 35 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Monad {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value }) 
 }
 
 static of(x) {
 return new Monad(x);
 }
 
 map (fn) {
 return Monad.of(fn(this.value));
 }
 
 bind (fn) {
 return fn(this.value);
 }
 }

Slide 36

Slide 36 text

#voxxeddaysLU voxxeddays.com/luxembourg/ DEMO?

Slide 37

Slide 37 text

#voxxeddaysLU voxxeddays.com/luxembourg/ map(function) I’m a Monad! bind(function)

Slide 38

Slide 38 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Maybe

Slide 39

Slide 39 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Pain points I’m Null! I’m Undefined!

Slide 40

Slide 40 text

#voxxeddaysLU voxxeddays.com/luxembourg/ bob = {
 id:'bob',
 address:{
 email:'[email protected]',
 country:'US'
 }
 };
 
 john = {
 id:'john',
 address:{
 country:'US'
 }
 };
 
 jane = {
 id:'jane'
 };
 
 buddies = [bob, john, jane]; getMailById = (id, buddies) => {
 let email = buddies
 .find(buddy => buddy.id == id)
 .address.email;
 
 if(email === null || email === undefined) {
 return "no email"
 }
 return email
 };

Slide 41

Slide 41 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 42

Slide 42 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Maybe None Some

Slide 43

Slide 43 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Maybe {
 
 static Some(x) { return new Some(x); }
 
 static None() { return new None(); }
 
 static fromNullable(x) {
 return (x !== null && x !== undefined)
 ? Maybe.Some(x)
 : Maybe.None();
 }
 
 static of(x) { return Maybe.Some(x); }
 }

Slide 44

Slide 44 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class None {
 constructor() {
 const value = null;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 map(fn) { return this; }
 
 bind (fn) { return this.value; }
 
 getOrElse(value) { return value; }
 
 isNone() { return true; } 
 isSome() { return false; }
 }

Slide 45

Slide 45 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Some {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 map(fn) { ⚠⚠⚠
 let res = fn(this.value);
 if(res == null || x == undefined) { return new None(); }
 return new Some(res);
 }
 
 bind (fn) { return fn(this.value); }
 
 getOrElse() { return this.value; }
 
 isNone() { return false; }
 
 isSome() { return true; }
 }

Slide 46

Slide 46 text

#voxxeddaysLU voxxeddays.com/luxembourg/ “functional” refactoring

Slide 47

Slide 47 text

#voxxeddaysLU voxxeddays.com/luxembourg/ bob = {
 id:'bob',
 address:{
 email:'[email protected]',
 country:'US'
 }
 };
 
 john = {
 id:'john',
 address:{
 country:'US'
 }
 };
 
 jane = {
 id:'jane'
 };
 
 buddies = [bob, john, jane]; getMailById = (id, buddies) => {
 return Maybe.fromNullable( buddies.find(buddy => buddy.id == id) )
 .map(buddy => buddy.address)
 .map(address => address.email)
 .getOrElse('no email!')
 };

Slide 48

Slide 48 text

#voxxeddaysLU voxxeddays.com/luxembourg/ DEMO?

Slide 49

Slide 49 text

#voxxeddaysLU voxxeddays.com/luxembourg/ map(function) I’m a Maybe! J’ai 2 sous types None Some bind(function)

Slide 50

Slide 50 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Either

Slide 51

Slide 51 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Either Left Right

Slide 52

Slide 52 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Either {
 
 static Left(x) { return new Left(x); }
 
 static Right(x) { return new Right(x); }
 
 static fromNullable(x) {
 return (x !== null && x !== undefined)
 ? Either.Right(x)
 : Either.Left();
 }
 
 static of(x) { return Either.Right(x); }
 }

Slide 53

Slide 53 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Left {
 constructor(err) {
 const value = err;
 Object.defineProperty(this, "value", { get: () => err })
 }
 
 map() { return this; }
 
 getOrElse(value) {return value; }
 
 orElse(fn) { return fn(this.value); }
 
 cata(leftFn, rightFn) { return leftFn(this.value); }
 }

Slide 54

Slide 54 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Right {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 map(fn) { return new Right(fn(this.value)); }
 
 getOrElse() { return this.value; } 
 orElse() { return this; }
 
 cata(leftFn, rightFn) { return rightFn(this.value); }
 }

Slide 55

Slide 55 text

#voxxeddaysLU voxxeddays.com/luxembourg/ utilisation

Slide 56

Slide 56 text

#voxxeddaysLU voxxeddays.com/luxembourg/ function getMonthName(mo) {
 mo = mo-1; // Adjust month number for array index (1=Jan, 12=Dec)
 var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
 "Aug", "Sep", "Oct", "Nov", "Dec"];
 if (months[mo] !== undefined) {
 return months[mo];
 } else {
 throw new UserException("Invalid Month Number");
 }
 }
 
 function getDayName(da) {
 da = da-1; // Adjust day number for array index
 var days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
 if (days[da] !== undefined) {
 return days[da];
 } else {
 throw new UserException("Invalid Day Number");
 }
 }

Slide 57

Slide 57 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 58

Slide 58 text

#voxxeddaysLU voxxeddays.com/luxembourg/ on “cache” les exceptions

Slide 59

Slide 59 text

#voxxeddaysLU voxxeddays.com/luxembourg/ giveMeMonthName = (monthNumber) => {
 try {
 return Either.Right(getMonthName(monthNumber));
 } catch (err) {
 return Either.Left(err);
 }
 };
 
 giveMeDayName = (dayNumber) => {
 try {
 return Either.Right(getDayName(dayNumber));
 } catch (err) {
 return Either.Left(err);
 }
 };

Slide 60

Slide 60 text

#voxxeddaysLU voxxeddays.com/luxembourg/ DEMO?

Slide 61

Slide 61 text

#voxxeddaysLU voxxeddays.com/luxembourg/ mais…

Slide 62

Slide 62 text

#voxxeddaysLU voxxeddays.com/luxembourg/ checkMonthAndDay = (monthNumber,dayNumber) => {
 try {
 let month = getMonthName(monthNumber);
 let day = getDayName(dayNumber);
 return Either.Right({month, day});
 } catch (err) {
 return Either.Left(err);
 }
 }

Slide 63

Slide 63 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 64

Slide 64 text

#voxxeddaysLU voxxeddays.com/luxembourg/ On ne trace pas toutes les erreurs

Slide 65

Slide 65 text

#voxxeddaysLU voxxeddays.com/luxembourg/ I’m an Either! J’ai 2 sous types Left Right cata( left function, right function ) bind(function) map(function) ou pas

Slide 66

Slide 66 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Validation

Slide 67

Slide 67 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Validation Fail Success

Slide 68

Slide 68 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Validation {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 static Success(x) { return new Success(x); }
 
 static Fail(errList) { return new Fail(errList); }
 
 static of(x) { return Validation.Success(x); }
 }

Slide 69

Slide 69 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Success {
 constructor(x) {
 const value = x;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 map(fn) { return new Success(fn(this.value)); }
 
 isSuccess() { return true; }
 isFail() { return false; }
 
 ap(otherContainer) { // has to be at least a functor
 return otherContainer instanceof Fail
 ? otherContainer
 : otherContainer.map(this.value)
 }
 
 cata(failureFn, successFn) { return successFn(this.value); }
 }

Slide 70

Slide 70 text

#voxxeddaysLU voxxeddays.com/luxembourg/ class Fail {
 constructor(err) {
 const value = err;
 Object.defineProperty(this, "value", { get: () => value })
 }
 
 map() { return this; }
 
 isSuccess() { return false; }
 isFail() { return true; }
 
 ap(otherContainer) { // has to be a functor
 return otherContainer instanceof Fail
 ? new Fail(this.value.concat(otherContainer.value))
 : this
 }
 
 cata(failureFn, successFn) { return failureFn(this.value); }
 }

Slide 71

Slide 71 text

#voxxeddaysLU voxxeddays.com/luxembourg/ exemple(s)

Slide 72

Slide 72 text

#voxxeddaysLU voxxeddays.com/luxembourg/ checkMonth = (monthNumber) => {
 try {
 let month = getMonthName(monthNumber);
 return Validation.Success(month)
 } catch (err) {
 return Validation.Fail([err])
 }
 };
 
 checkDay = (dayNumber) => {
 try {
 let day = getDayName(dayNumber);
 return Validation.Success(day)
 } catch (err) {
 return Validation.Fail([err])
 }
 };

Slide 73

Slide 73 text

#voxxeddaysLU voxxeddays.com/luxembourg/ DEMO?

Slide 74

Slide 74 text

#voxxeddaysLU voxxeddays.com/luxembourg/ I’m a Validation! J’ai 2 sous types Fail Success cata( failureFn function, successFn function ) ap(validation) map(function)

Slide 75

Slide 75 text

#voxxeddaysLU voxxeddays.com/luxembourg/

Slide 76

Slide 76 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Paysage Fonctionnel côté JS

Slide 77

Slide 77 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Quelques libs > Monet.js: https:/ /cwmyers.github.io/monet.js/ > Ramda.js: http:/ /ramdajs.com/0.21.0/index.html > Underscore: http:/ /underscorejs.org/ > Lodash: https:/ /lodash.com/ > Folktale: http:/ /folktalejs.org/ > Fantasy Land: https:/ /github.com/fantasyland

Slide 78

Slide 78 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Ressources

Slide 79

Slide 79 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Lectures Mostly Adequate Guide (Brian Lonsdorf): https:/ /www.gitbook.com/book/drboolean/ mostly-adequate-guide/details Functional Programming in Java (Pierre-Yves Saumont): https:/ /www.manning.com/ books/functional-programming-in-java Functional Programming in JavaScript (Luis Atencio): https:/ /www.manning.com/books/ functional-programming-in-javascript Functional Programming in Scala (Paul Chiusano and Rúnar Bjarnason): https:/ / www.manning.com/books/functional-programming-in-scala Le code source de Golo: https:/ /github.com/eclipse/golo-lang/blob/master/src/main/golo/errors.golo https:/ /github.com/eclipse/golo-lang/blob/master/src/main/java/gololang/error/ Result.java

Slide 80

Slide 80 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Talks Gérer les erreurs avec l'aide du système de types de Scala ! (David Sferruzza): https:/ /www.youtube.com/watch?v=TwJQKrZ23Vs TDD, comme dans Type-Directed Development (Clément Delafargue): https:/ /www.youtube.com/watch?v=XhcgCF0xXRs

Slide 81

Slide 81 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Remerciements

Slide 82

Slide 82 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Merci > à vous > Loïc Descotte @loic_d > Julien Ponge @jponge > Thierry Chantier @titimoby > Etienne Issartial | CommitStrip > Clément Delafargue @clementd > @voxxed_lu

Slide 83

Slide 83 text

#voxxeddaysLU voxxeddays.com/luxembourg/ Questions https:/ /github.com/k33g/ voxxed.lu.functional.js/issues https://github.com/k33g/voxxed.lu.functional.js