Slide 1

Slide 1 text

PROG FONCTIONNELLE EN JAVASCRIPT, AVEC UN PEU DE SCALA MAIS PAS QUE 1 — @GDGLille

Slide 2

Slide 2 text

Philippe Charrière @k33g_org @k33g > Tech evangelist & CSO @Clever_Cloud > Core committer https://github.com/eclipse/golo-lang I ❤ JavaScript, I " Java, I JVM, I Golo, I % Scala (depuis peu…) ! 2 — @GDGLille

Slide 3

Slide 3 text

AGENDA ⚠ il va y avoir du Scala la PF et moi quelques bases container, functor, monad(e) Monet.js: Identity, Maybe, Either Autres Monades Union types 3 — @GDGLille

Slide 4

Slide 4 text

QUI FAIT DE LA PF DANS LA SALLE? 4 — @GDGLille

Slide 5

Slide 5 text

FP AND ME OU, "MAIS QU'EST CE QUE JE FAIS ICI?" 5 — @GDGLille

Slide 6

Slide 6 text

FP AND ME HTTP://ADIT.IO/POSTS/2013-04-17-FUNCTORS,APPLICATIVES,ANDMONADSIN_PICTURES.HTML 6 — @GDGLille

Slide 7

Slide 7 text

FP AND ME A monad is just a monoid in the category of endofunctors, what's the problem? — Philip Wadler 7 — @GDGLille

Slide 8

Slide 8 text

FP AND ME 8 — @GDGLille

Slide 9

Slide 9 text

MA RÉVÉLATION https://github.com/MostlyAdequate/mostly-adequate-guide 9 — @GDGLille

Slide 10

Slide 10 text

FP AND ME ⚠ DISCLAIMER AVANT DE CONTINUER Tout le monde ne sera pas forcément d'accord L'objectif c'est de commencer à comprendre 2, 3 choses 10 — @GDGLille

Slide 11

Slide 11 text

C'EST PARTI ... ⚠ LES EXEMPLES SONT (PRESQUE TOUS) EN ES2015 + NODE 11 — @GDGLille

Slide 12

Slide 12 text

MAIS POURQUOI DU JAVASCRIPT 12 — @GDGLille

Slide 13

Slide 13 text

MAIS POURQUOI DU JAVASCRIPT > facile à lire si si > simple à utiliser ES 2015 > fonctionnel depuis longtemps > encore plus depuis ECMAScript 5 13 — @GDGLille

Slide 14

Slide 14 text

QUELQUES BASES 14 — @GDGLille

Slide 15

Slide 15 text

KEY POINTS > pure function > function as input & output > no iteration > (im)mutability 15 — @GDGLille

Slide 16

Slide 16 text

PURE FUNCTIONS 16 — @GDGLille

Slide 17

Slide 17 text

PURE FUNCTIONS > Pour éviter les effets de bord > Toujours retourner le même résultat pour les mêmes paramètres 17 — @GDGLille

Slide 18

Slide 18 text

NOT PURE FUNCTION var name = "Bob"; function badHey() { console.log(`Hello ${name}`); } badHey(); // I'm not sure that `hey()` shows always "Bob" // " can interact with `var name = "Bob";` // `hey()` -> void => can't test 18 — @GDGLille

Slide 19

Slide 19 text

PURE FUNCTION function goodHey({name}) { // named parameter return `Hello ${name}`; } console.log(goodHey({name:"Bob"})); 19 — @GDGLille

Slide 20

Slide 20 text

CURRYING 20 — @GDGLille

Slide 21

Slide 21 text

CURRYING > Il est possible d'appeler une fonction avec moins d'arguments qu'elle n'en attend > Elle retournera une fonction qui attend les arguments restants 21 — @GDGLille

Slide 22

Slide 22 text

AVANT function youAreSo(name, adjective) { return `${name}, you are so ${adjective}` } youAreSo("Bob", " ✨ ") // amazing: Bob, you are so youAreSo("Sam", " "#$ ") // lovely: Sam, you are so 22 — @GDGLille

Slide 23

Slide 23 text

MAINTENANT AVEC LE CURRYING // a function that returns a function that returns a string function youAreSo(adjective) { return function(name) { return `${name}, you are so ${adjective}` } } // "shortcuts" let youAreSoAmazing = youAreSo(" ✨ "); let youAreSoLovely = youAreSo(" "#$ "); youAreSoAmazing("Bob") youAreSoLovely("Sam") 23 — @GDGLille

Slide 24

Slide 24 text

CURRYING & PF > moins verbeuse > plus agréable > ré-utilisation 24 — @GDGLille

Slide 25

Slide 25 text

COMPOSITION let wow = (name) => youAreSoAmazing(youAreSoLovely(name)) wow("Jane") // Jane, you are so !"# , you are so 25 — @GDGLille

Slide 26

Slide 26 text

NO ITERATIONS 26 — @GDGLille

Slide 27

Slide 27 text

NO ITERATIONS Pour faire "plus fonctionnel": > ne pas itérer (for, while) pour transformer les données > préférer map, filter, reduce, ... > cf. Java 8 -> streams 27 — @GDGLille

Slide 28

Slide 28 text

NO ITERATIONS ! 28 — @GDGLille

Slide 29

Slide 29 text

NO ITERATIONS PRÉPARER UN KEBAB: > choisir des ingrédients (sans frites, sans oignons, ...) > découper > tout mettre ensemble 29 — @GDGLille

Slide 30

Slide 30 text

NO ITERATIONS let aliments = [ " ! " , " " " , " # " , " $ " , " % " , " & " // ' pas d'emoji oignons ] 30 — @GDGLille

Slide 31

Slide 31 text

NO ITERATIONS // actions function decouper(aliment) { return `morceaux de ${aliment}`; } // if not frites return true function sansFrite(aliment) { return aliment !== " ! "; } // if not oignon return true function sansOignon(aliment) { return aliment !== " " "; } 31 — @GDGLille

Slide 32

Slide 32 text

NO ITERATIONS: CHOISIR ET DÉCOUPER // ingrédients pour faire mon Kebab let ingredients = aliments .filter(sansFrite) // ⏩ new list .filter(sansOignon) // ⏩ new list .map(decouper) // ⏩ new list (transformer en un autre []) console.log("ingrédients:", ingredients) 32 — @GDGLille

Slide 33

Slide 33 text

NO ITERATIONS: CHOISIR ET DÉCOUPER NOUVEAU TABLEAU ingrédients: [ 'morceaux de ! ', 'morceaux de " ', 'morceaux de # ', 'morceaux de $ ' ] 33 — @GDGLille

Slide 34

Slide 34 text

NO ITERATIONS: TOUT METTRE ENSEMBLE (À PLAT) // ⚡ combiner(transformer) les ingredients let kebab = ingredients.reduce( function(resultatIntermediaire, ingredient) { return resultatIntermediaire + ingredient + " " }, " " avec: " ) console.log(kebab) " " avec: morceaux de # morceaux de morceaux de morceaux de " 34 — @GDGLille

Slide 35

Slide 35 text

(IM)MUTABILITY éviter les changements utiliser des données immutables 35 — @GDGLille

Slide 36

Slide 36 text

(IM)MUTABILITY aliments[5] = " ! "; // mutability is bad let ingredients = aliments.filter(sansFrite).filter(sansOignon).map(decouper) let kebab = ingredients.reduce((resultatIntermediaire, ingredient) => { return resultatIntermediaire + ingredient + " " }, " " avec: ") console.log(kebab) // " avec: morceaux // de # morceaux de $ morceaux de % morceaux de morceaux de // who is the '( who put ! in my " ❓ 36 — @GDGLille

Slide 37

Slide 37 text

(IM)MUTABILITY > Ne jamais trandformer un tableau (liste, collection, ...) directement > utiliser map pour obtenir un nouveau tableau 37 — @GDGLille

Slide 38

Slide 38 text

(IM)MUTABILITY let bananesAlaPlaceDesOignons = (aliment) => aliment == " ! " ? " " : aliment let aliments = [' # ', ' $ ', ' % ', ' ', ' ', ' '] aliments.map(bananesAlaPlaceDesOignons) // nouveau tableau // [ ' # ', ' $ ', ' % ', ' & ', ' ' ', ' ' ] 38 — @GDGLille

Slide 39

Slide 39 text

(IM)MUTABILITY: MES RECETTES PRÉFÉRÉES let myFavoriteRecipe = aliments.filter(sansFrite).filter(sansOignon) .map(decouper) let myWeirdReceipe = aliments .map(bananesAlaPlaceDesOignons) // ( new list) .filter(sansFrite) .map(decouper) 39 — @GDGLille

Slide 40

Slide 40 text

! EN SCALA 40 — @GDGLille

Slide 41

Slide 41 text

! EN SCALA val aliments = List(" ! ", " " ", " # ", " ", " ", " ") // === action recette === def decouper(aliment: String): String = s"morceaux de $aliment" // === choix aliments === def sansFrite(aliment: String): Boolean = aliment != " " def sansOignon(aliment: String): Boolean = aliment != " " // === filtrer, puis découper === val ingredients = aliments .filter(sansFrite) .filter(sansOignon) .map(decouper) 41 — @GDGLille

Slide 42

Slide 42 text

! EN SCALA // === assembler ==== aka reduce aliments .filter(sansFrite) .map(decouper) .fold(" ! avec: ") { (tmp, ingredient) => tmp + ingredient + " "} 42 — @GDGLille

Slide 43

Slide 43 text

WRAPPER (BOCAL) 43 — @GDGLille

Slide 44

Slide 44 text

WRAPPER (BOCAL) 44 — @GDGLille

Slide 45

Slide 45 text

WRAPPER ❓ EN JAVASCRIPT class Wrapper { constructor(x) { const value = x; Object.defineProperty(this, "value", { get: () => value }) } static of(x) { return new Wrapper(x); } } 45 — @GDGLille

Slide 46

Slide 46 text

WRAPPER ❓ EN JAVA public class Wrapper { private T value; public T getValue() { return this.value; } public Wrapper(T value) { this.value = value; } } 46 — @GDGLille

Slide 47

Slide 47 text

FUNCTOR 47 — @GDGLille

Slide 48

Slide 48 text

FUNCTOR OPÉRATIONS 48 — @GDGLille

Slide 49

Slide 49 text

FUNCTOR NOUVELLE VALEUR 49 — @GDGLille

Slide 50

Slide 50 text

FUNCTOR IMMUTABLE 50 — @GDGLille

Slide 51

Slide 51 text

FUNCTOR ET AINSI DE SUITE ... 51 — @GDGLille

Slide 52

Slide 52 text

FUNCTOR ... ET AINSI DE SUITE ... 52 — @GDGLille

Slide 53

Slide 53 text

FUNCTOR class Functor extends Wrapper { constructor(x) { super(x); } static of(x) {return new Functor(x);} ! map (fn) { return new this.constructor(fn(this.value)); // return new Functor(fn(this.value)) } } 53 — @GDGLille

Slide 54

Slide 54 text

FUNCTOR ❓ EN JAVA public class Functor extends Wrapper { public Functor(T value) { super(value); } public Functor map(Function f) { return new Functor(f.apply((T) this.getValue())); } } 54 — @GDGLille

Slide 55

Slide 55 text

FUNCTOR > donc un Functor a une méthode map() > et les tableaux en JavaScript aussi 55 — @GDGLille

Slide 56

Slide 56 text

MONAD 56 — @GDGLille

Slide 57

Slide 57 text

MONAD 57 — @GDGLille

Slide 58

Slide 58 text

MONAD 58 — @GDGLille

Slide 59

Slide 59 text

MONAD 59 — @GDGLille

Slide 60

Slide 60 text

MONAD class Monad extends Functor { constructor(x) { super(x); } static of(x) {return new Monad(x);} /* So, I'm a monad because I have a flatMap method */ ! flatMap (fn) { return fn(this.value); } } 60 — @GDGLille

Slide 61

Slide 61 text

MONAD ❓ EN JAVA public class Monad extends Wrapper { public Monad(T value) { super(value); } public Monad map(Function f) { return new Monad(f.apply((T) this.getValue())); } public Monad flatMap(Function> f) { return f.apply((T) this.getValue()); } } 61 — @GDGLille

Slide 62

Slide 62 text

MONAD > map() > flatMap() 62 — @GDGLille

Slide 63

Slide 63 text

MONET.JS 63 — @GDGLille

Slide 64

Slide 64 text

MONET.JS https://cwmyers.github.io/monet.js/ 64 — @GDGLille

Slide 65

Slide 65 text

IDENTITY AVEC MONET COMME LA MONAD(E) DE TOUTE À L'HEURE 65 — @GDGLille

Slide 66

Slide 66 text

IDENTITY AVEC MONET: MAP const monet = require('monet'); let content = monet.Identity("Hello ") let h1 = value => `

${value}

` let body = value => `${value}` let html = value => `${value}` console.log( content.map(h1).map(body).map(html).get() ) //

Hello !

66 — @GDGLille

Slide 67

Slide 67 text

IDENTITY AVEC MONET: FLATMAP let content = monet.Identity("Hello ! ") let h1 = value => `

${value}

` let bold = value => `${value}` let italic = value => `${value}` // component let title = txt => monet.Identity(txt).map(bold).map(h1) console.log(content.map(title).get()) // { val: '

Hello !

' } console.log(content.flatMap(title).get()) //

Hello !

67 — @GDGLille

Slide 68

Slide 68 text

IDENTITY UTILE 68 — @GDGLille

Slide 69

Slide 69 text

IDENTITY EN SCALA case class IntMonad(val value: Int) { def map(fn: Int => Int) = { val res = fn(this.value); IntMonad(res) // implicit return } def flatMap(fn: Int => IntMonad) = { fn(this.value) } } 69 — @GDGLille

Slide 70

Slide 70 text

IDENTITY EN SCALA val prixDeDepart = IntMonad(10000) val optionClim = (prix: Int) => prix + 2000 val interieurCuir = (prix: Int) => prix + 5000 val vitreTeintees = (prix: Int) => prix + 3000 prixDeDepart .map(optionClim) .map(interieurCuir) .map(vitreTeintees).value 70 — @GDGLille

Slide 71

Slide 71 text

UN PEU PLUS LOIN ... 71 — @GDGLille

Slide 72

Slide 72 text

GESTION DES 72 — @GDGLille

Slide 73

Slide 73 text

NULL & UNDEFINED pain points 73 — @GDGLille

Slide 74

Slide 74 text

74 — @GDGLille

Slide 75

Slide 75 text

MAYBE AVEC MONET 75 — @GDGLille

Slide 76

Slide 76 text

MAYBE AVEC MONET orSome() const monet = require('monet'); let a = monet.Maybe.fromNull(42) // { isValue: true, val: 42 } console.log(a.orSome(0)) // 42 let b = monet.Maybe.fromNull(null) // { isValue: false, val: null } console.log(b.orSome(0)) // 0 76 — @GDGLille

Slide 77

Slide 77 text

MAYBE AVEC MONET orElse() const monet = require('monet'); let maybe = monet.Maybe.fromNull(null) // console.log( maybe.orElse(monet.Maybe.Some(" ! ")) // { isValue: true, val: ' ' } ) let maybeAgain = monet.Maybe.fromNull(" ") console.log( maybeAgain.orElse(monet.Maybe.Some(" ")) // { isValue: true, val: ' ' } ) 77 — @GDGLille

Slide 78

Slide 78 text

MAYBE AVEC MONET UTILE 78 — @GDGLille

Slide 79

Slide 79 text

MAYBE AVEC MONET - UTILE - RECHERCHES let getUserById = (id) => { let users = [ {id:1, name:"bob", avatar:" "}, {id:2, name:"sam", avatar:" "}, {id:3, name:"jane", avatar:" "}, {id:4, name:"john", avatar:" "} ] return monet.Maybe.fromNull(users.find(u => u.id == id)) } 79 — @GDGLille

Slide 80

Slide 80 text

MAYBE AVEC MONET - UTILE - RECHERCHES getUserById(2) .orSome(" ⚠ no user") // { id: 2, name: 'sam', avatar: ' ' } getUserById(7) .orSome(" ⚠ no user") // ⚠ no user 80 — @GDGLille

Slide 81

Slide 81 text

MAYBE AVEC MONET - UTILE - .map() getUserById(2) .map((user) => user.avatar ) .orSome(" ! ") // " getUserById(7) .map((user) => user.avatar ) .orSome(" ! ") // ! 81 — @GDGLille

Slide 82

Slide 82 text

MAYBE AVEC MONET CATAMORPHISME 82 — @GDGLille

Slide 83

Slide 83 text

CATAMORPHISME "Dans la théorie des catégories, le concept de catamorphisme (du Grec: κατα- = vers le bas; morphisme = forme) dénote l'unique homomorphisme pour une algèbre initiale." "En programmation fonctionnelle, un catamorphisme est une généralisation de la fonction fold sur les listes au cadre de types algébriques de données quelconques pouvant être décrit comme des algèbres initiales." 83 — @GDGLille

Slide 84

Slide 84 text

CATAMORPHISME getUserById(1).cata( () => { // left return "this user does not exist" }, (user) => { // right return "Hello ${user.avatar}" } ) 84 — @GDGLille

Slide 85

Slide 85 text

ET EN SCALA ! 85 — @GDGLille

Slide 86

Slide 86 text

OPTION == MAYBE case class User(id: String, avatar: String) val users = List( User("panda", " ! "), User("fox", " " "), User("lion", " # ") ) 86 — @GDGLille

Slide 87

Slide 87 text

find() ALWAYS RETURN AN Option users.find(user => user.id == "panda") // Some(User(panda, ! )) users.find(user => user.id == "tiger") // None 87 — @GDGLille

Slide 88

Slide 88 text

DONC JE PEUX FAIRE CECI: users .find(user => user.id == "panda") .map(user => user.avatar) .getOrElse(" ! ") // " or ! 88 — @GDGLille

Slide 89

Slide 89 text

OU CELA: (CATAMORPHISME LIKE) users.find(user => user.id == "fox") match { case None => "this user does not exist" case Some(user) => s"Hello ${user.avatar}" } // ! 89 — @GDGLille

Slide 90

Slide 90 text

! IL Y A flatMap AUSSI case class User(id: Option[String], avatar: Option[String]) val users = List( User(Option("panda"), Option(" ! ")), User(Option("fox"), Option(" " ")), User(Option("lion"), Option(" # ")) ) println( users.find(user => user.id.get.equals("fox")) .flatMap(user => user.avatar) .getOrElse(" $ ") ) 90 — @GDGLille

Slide 91

Slide 91 text

91 — @GDGLille

Slide 92

Slide 92 text

EITHER AVEC MONET 92 — @GDGLille

Slide 93

Slide 93 text

divide function divide(a, b) { try { if(typeof a !== "number") throw new Error(" a is not a number") if(typeof b !== "number") throw new Error(" b is not a number") if(b==0) throw new Error(" ! /0") return monet.Either.Right(a/b); } catch(err) { return monet.Either.Left(err.message) } } 93 — @GDGLille

Slide 94

Slide 94 text

divide let result1 = divide(4,5) result1.isRight() ? console.log(result1.right()) : console.log(result1.left()) // 0.8 let result2 = divide(4,0) result2.isRight() ? console.log(result2.right()) : console.log(result2.left()) // ! /0 divide(4,"quatre").cata(leftError => { console.error(leftError) }, rightSuccess => { console.info(rightSuccess) }) // ! b is not a number 94 — @GDGLille

Slide 95

Slide 95 text

ET EN SCALA !! 95 — @GDGLille

Slide 96

Slide 96 text

CÔTÉ SERVEUR EN JAVASCRIPT let users = [" ! ", " " ", " # ", " "] app.get('/users/:id', (req, res) => { let user = users[parseInt(req.params.id)] res.send(user) }); 96 — @GDGLille

Slide 97

Slide 97 text

EITHER AVEC SCALA def getUser(uri: String, id: Int): Either[String, Any] = { try { fromURL(s"http://localhost:7070/${uri}/${id.toString}").mkString match { case "" => Left(" ! Empty") case content:String => Right(content) } } catch { case e: Exception => Left(s" ! ${e.toString}") } } 97 — @GDGLille

Slide 98

Slide 98 text

EITHER (UTILISATION) getUser("users", 3) match { case Left(err) => println(err) case Right(content) => println(content) } // ! getUser("users",8) match { case Left(err) => println(err) case Right(content) => println(content) } // " Empty getUser("user",8) match { case Left(err) => println(err) case Right(content) => println(content) } // " java.io.FileNotFoundException: http://localhost:7070/user/8 98 — @GDGLille

Slide 99

Slide 99 text

MORE "STYLISH" WITH Try def getUser(uri: String, id: Int): Try[String] = { Try( fromURL(s"http://localhost:7070/${uri}/${id.toString}").mkString ) } getUser("users", 3) match { ! case Failure(fail) => println(s" " ${fail.toString}") ! case Success(content) => content match { case "" => println(" " Empty") case _ => println(content) } } 99 — @GDGLille

Slide 100

Slide 100 text

INTÉRESSANT AVEC VERT.X router.get("/divide/:a/:b").handler(context => { Try( context.request.getParam("a").get.toInt / context.request.getParam("b").get.toInt ) match { case Failure(e) => context.json(new JsonObject().put("message", e.getMessage)) case Success(result) => context.json(new JsonObject().put("result", result)) } }) 100 — @GDGLille

Slide 101

Slide 101 text

BON, C'EST FINI ... ... POUR LA PARTIE "MONET.JS" MAIS IL Y A PLEIN D'AUTRES CHOSES JOUEZ AVEC 101 — @GDGLille

Slide 102

Slide 102 text

AUTRES MONADES 102 — @GDGLille

Slide 103

Slide 103 text

COLLECTIONS (SCALA): map case class Toon(pseudo: String, avatar: String) val toons = List( Toon("Bob", " ! "), Toon("Jane", " " "), Toon("Sam", " # "), Toon("John", " $ ") ) val myList = toons.map(toon => toon.pseudo + toon.avatar) // List(Bob ! , Jane " , Sam # , John ) 103 — @GDGLille

Slide 104

Slide 104 text

C'EST PLUS MOCHE EN JAVA List myList = toons .stream() .map(toon -> toon.pseudo + toon.avatar) .collect(Collectors.toList()); 104 — @GDGLille

Slide 105

Slide 105 text

COLLECTIONS (SCALA): flatMap case class Toon(pseudo: String, avatar: String, buddies: List[Toon]= List()) val toons = List( Toon("Bob", " ! ", List(Toon("Ted", " " "), Toon("Polo", " "))), Toon("Jane", " $ ", List(Toon("Zed", " "), Toon("Grou", " "))), Toon("Sam", " ' ", List(Toon("Kate", " "), Toon("Nike", " "))), Toon("John", " * ", List(Toon("Ray", " "), Toon("Zoe", " "))) ) val myList = toons.flatMap(toon => toon.buddies).map(toon => toon.avatar) //List( " , # , % , & , ( , ) , + , , ) 105 — @GDGLille

Slide 106

Slide 106 text

UNION TYPES ! 106 — @GDGLille

Slide 107

Slide 107 text

UNION TYPES Ceylon, Golo, ... Un type avec plusieurs sous-types, et il est un de ces sous-types, mais toujours un seul à la fois 107 — @GDGLille

Slide 108

Slide 108 text

UNION TYPES EN TYPESCRIPT 108 — @GDGLille

Slide 109

Slide 109 text

UNION TYPES | TYPESCRIPT class Yum { value: String constructor(value) { this.value = value; } } class Yuck { value: String constructor(value) { this.value = value; } } class Dunno { value: String constructor(value) { this.value = value; } } 109 — @GDGLille

Slide 110

Slide 110 text

UNION TYPES | TYPESCRIPT function eat(food: String): Yuck | Yum | Dunno { if(food==' ! ') return new Yum(food) if(food==' " ') return new Yuck(food) return new Dunno(food) } console.log(eat(' ! ') instanceof Yum) console.log(eat(' ! ') instanceof Yuck) console.log(eat(' # ') instanceof Dunno) 110 — @GDGLille

Slide 111

Slide 111 text

EN GOLO ÇA DONNERAIT CECI: union SomeThing = { Yum = { value } # good Yuck = { value } # bad Dunno = { value } # I don't know } let eat = |food| { if food is " ! " { return SomeThing.Yum(food)} if food is " " " { return SomeThing.Yuck(food)} return SomeThing.Dunno(food) } let res = eat(" ! ") match { when res: isYum() then println(" # ") when res: isYuck() then println(" $ ") otherwise " % " } 111 — @GDGLille

Slide 112

Slide 112 text

UNION TYPES EN JAVASCRIPT 112 — @GDGLille

Slide 113

Slide 113 text

UNION-TYPE.JS https://github.com/paldepind/union-type 113 — @GDGLille

Slide 114

Slide 114 text

UNION-TYPE.JS let SomeThing = Type({ Yum:{value: String}, Yuck:{value: String} }) let good = SomeThing.Yum(' ! ') let bad = SomeThing.Yuck(' " ') 114 — @GDGLille

Slide 115

Slide 115 text

UNION-TYPE.JS good.case({ Yum: (v) => { console.log(" ", v) }, Yuck: (v) => { console.log(" ", v) } }) bad.case({ Yum: (v) => { console.log(" ", v) }, Yuck: (v) => { console.log(" ", v) } }) 115 — @GDGLille

Slide 116

Slide 116 text

C'EST POUR ÇA QUE J LE JAVASCRIPT Tout est possible simplement 116 — @GDGLille

Slide 117

Slide 117 text

BTW Scala c'est simple comme du JS finalement ! 117 — @GDGLille

Slide 118

Slide 118 text

QUELQUES RESSOURCES 118 — @GDGLille

Slide 119

Slide 119 text

LIBS & REPOS 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 119 — @GDGLille

Slide 120

Slide 120 text

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 120 — @GDGLille

Slide 121

Slide 121 text

CODES SOURCE & ARTICLES 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 Les monades en PHP: HTTP://MCAMUZAT.GITHUB.IO/BLOG/2015/11/11/LES-MONADES-EN-PHP-CEST- POSSIBLE-DOT/ 121 — @GDGLille

Slide 122

Slide 122 text

TALKS Learning Functional Programming with JavaScript - JSUnconf 2016 ANJANA VAKIL HTTPS://WWW.YOUTUBE.COM/WATCH?V=E-5OBM1G_FY 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 122 — @GDGLille

Slide 123

Slide 123 text

REMERCIEMENTS Vous @GDGLille @loic_d, @jponge, @clementd, @yannick_loiseau, @titimoby 123 — @GDGLille

Slide 124

Slide 124 text

QUESTIONS 124 — @GDGLille

Slide 125

Slide 125 text

125 — @GDGLille