Slide 1

Slide 1 text

PROG FONCTIONNELLE ! & JAVASCRIPT 1 — @MontpellierJug

Slide 2

Slide 2 text

@K33G_ORG ! HTTP://K33G.GITHUB.IO/ HTTPS://GITHUB.COM/K33G/FILES ! 2 — @MontpellierJug

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

QUI FAIT DE LA PF? 4 — @MontpellierJug

Slide 5

Slide 5 text

FP AND ME ! 5 — @MontpellierJug

Slide 6

Slide 6 text

❤ @CommitStrip 6 — @MontpellierJug

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

FP AND ME ! 8 — @MontpellierJug

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

FP AND ME ! 10 — @MontpellierJug

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

MAIS POURQUOI DU JAVASCRIPT !❓ 14 — @MontpellierJug

Slide 15

Slide 15 text

MAIS POURQUOI DU JAVASCRIPT !❓ > facile à lire si si > simple à utiliser ES 2015 > fonctionnel depuis longtemps > encore plus depuis ECMAScript 5 15 — @MontpellierJug

Slide 16

Slide 16 text

QUELQUES BASES 16 — @MontpellierJug

Slide 17

Slide 17 text

KEY POINTS > imperative vs functional > pure function > function as input & output > no iteration > (im)mutability 17 — @MontpellierJug

Slide 18

Slide 18 text

IMPERATIVE VS FUNCTIONAL 18 — @MontpellierJug

Slide 19

Slide 19 text

IMPERATIVE STYLE ! "BASIC LIKE" var name1 = "Bob"; var message1 = "Hello"; var name2 = "Sam"; var message2 = "Hi"; console.log(`${message1} ${name1}`); console.log(`${message2} ${name2}`); 19 — @MontpellierJug

Slide 20

Slide 20 text

FUNCTIONAL STYLE ! function hey({message, name}) { //! named parameter return `${message} ${name}`; } function hi({name}) { return hey({message: "Hi", name: name}) } function hello({name}) { return hey({message: "Hello", name: name}) } console.log(hello({name:"Bob"})); // ! reuse console.log(hi({name:"Sam"})); // ! reuse 20 — @MontpellierJug

Slide 21

Slide 21 text

PURE FUNCTIONS 21 — @MontpellierJug

Slide 22

Slide 22 text

PURE FUNCTIONS Avoid side effect, using pure function use "pure function": - return always the same output for the same input not pure: - console.log() <> output, ... - using a variable declared outside the function ! It's not always possible " Think "purely" as possible 22 — @MontpellierJug

Slide 23

Slide 23 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 " 23 — @MontpellierJug

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

FUNCTIONS AS INPUT AND OUTPUT 25 — @MontpellierJug

Slide 26

Slide 26 text

FUNCTIONS AS INPUT AND OUTPUT a function that returns a function that returns something etc... 26 — @MontpellierJug

Slide 27

Slide 27 text

FUNCTIONS AS INPUT AND OUTPUT // 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(""#$"); 27 — @MontpellierJug

Slide 28

Slide 28 text

FUNCTIONS AS INPUT AND OUTPUT // simplify code, lisibility, reuse console.log( youAreSoAmazing("Bob") ); // Bob, you are so ✨ console.log( youAreSoLovely("Sam") ); // Sam, you are so "#$ 28 — @MontpellierJug

Slide 29

Slide 29 text

NO ITERATIONS ⚠ 29 — @MontpellierJug

Slide 30

Slide 30 text

NO ITERATIONS More "functional style" don't iterate, (for, while) to transform data -> use map, reduce, filter 30 — @MontpellierJug

Slide 31

Slide 31 text

NO ITERATIONS ! 31 — @MontpellierJug

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 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 !== """; } 34 — @MontpellierJug

Slide 35

Slide 35 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) 35 — @MontpellierJug

Slide 36

Slide 36 text

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

Slide 37

Slide 37 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) 37 — @MontpellierJug

Slide 38

Slide 38 text

NO ITERATIONS: TOUT METTRE ENSEMBLE "! avec: morceaux de " morceaux de # morceaux de $ morceaux de %" 38 — @MontpellierJug

Slide 39

Slide 39 text

NO ITERATIONS [00-bases/kebab.js - ES2015 version] 39 — @MontpellierJug

Slide 40

Slide 40 text

(IM)MUTABILITY avoid mutability use immutable data 40 — @MontpellierJug

Slide 41

Slide 41 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 ) ❓ 41 — @MontpellierJug

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 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) 44 — @MontpellierJug

Slide 45

Slide 45 text

CONTAINER❓ 45 — @MontpellierJug

Slide 46

Slide 46 text

CONTAINER❓ 46 — @MontpellierJug

Slide 47

Slide 47 text

CONTAINER❓ class Container { constructor(x) { const value = x; Object.defineProperty(this, "value", { get: () => value }) } static of(x) { return new Container(x); } } 47 — @MontpellierJug

Slide 48

Slide 48 text

CONTAINER❓ EN JAVA public class Container { private T value; public T getValue() { return this.value; } public Container(T value) { this.value = value; } } 48 — @MontpellierJug

Slide 49

Slide 49 text

[CONTAINER] ☕ JAVA CODE? > 00-bases-java/Container.java > 00-bases-java/ContainerTest.java 49 — @MontpellierJug

Slide 50

Slide 50 text

CONTAINER > "conserver" des valeurs ! 50 — @MontpellierJug

Slide 51

Slide 51 text

FUNCTOR❓ 51 — @MontpellierJug

Slide 52

Slide 52 text

FUNCTOR❓ OPÉRATIONS 52 — @MontpellierJug

Slide 53

Slide 53 text

FUNCTOR❓ NOUVELLE VALEUR 53 — @MontpellierJug

Slide 54

Slide 54 text

FUNCTOR❓ IMMUTABLE 54 — @MontpellierJug

Slide 55

Slide 55 text

FUNCTOR❓ ET AINSI DE SUITE ... 55 — @MontpellierJug

Slide 56

Slide 56 text

FUNCTOR❓ ... ET AINSI DE SUITE ... 56 — @MontpellierJug

Slide 57

Slide 57 text

FUNCTOR❓ class Functor extends Container { 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)) } } 57 — @MontpellierJug

Slide 58

Slide 58 text

[FUNCTOR] CHT'ITE DEMO JS > 00-bases/functor.tests.js 58 — @MontpellierJug

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

FUNCTOR > map() > Array == Functor ! 60 — @MontpellierJug

Slide 61

Slide 61 text

MONAD❓ 61 — @MontpellierJug

Slide 62

Slide 62 text

MONAD❓ 62 — @MontpellierJug

Slide 63

Slide 63 text

MONAD❓ 63 — @MontpellierJug

Slide 64

Slide 64 text

MONAD❓ 64 — @MontpellierJug

Slide 65

Slide 65 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); } } 65 — @MontpellierJug

Slide 66

Slide 66 text

MONAD❓ EN JAVA public class Monad extends Container { 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()); } } 66 — @MontpellierJug

Slide 67

Slide 67 text

[MONAD] CHT'ITE DEMO JS > 00-bases/monad.tests1.js > 00-bases/monad.tests2.js 67 — @MontpellierJug

Slide 68

Slide 68 text

MONAD > map() > flatMap() ! 68 — @MontpellierJug

Slide 69

Slide 69 text

MONET.JS❓ 69 — @MontpellierJug

Slide 70

Slide 70 text

MONET.JS❓ https://cwmyers.github.io/monet.js/ 70 — @MontpellierJug

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

IDENTITY AVEC MONET const monet = require('monet'); let panda = monet.Identity('!'); let addRabbit = (me) => me + """; let buddies = panda .map(addRabbit).map(addRabbit) .map(b => b + "#") console.log(buddies) // { val: '!""#' } console.log(buddies.get()) // !""# 72 — @MontpellierJug

Slide 73

Slide 73 text

IDENTITY AVEC MONET UNE MONADE DANS UNE MONADE let addTiger = (me) => monet.Identity(me + '!') let otherBuddies = panda .map(addRabbit) .map(addRabbit) .map(addTiger) console.log(otherBuddies) // { val: { val: '"##!' } } console.log(otherBuddies.get()) // { val: '"##!' } 73 — @MontpellierJug

Slide 74

Slide 74 text

IDENTITY AVEC MONET ON APLATIT ... let addTiger = (me) => monet.Identity(me + '!') let otherBuddies = panda .map(addRabbit) .map(addRabbit) .flatMap(addTiger) console.log(otherBuddies) // { val: '"##!' } console.log(otherBuddies.get()) // "##! 74 — @MontpellierJug

Slide 75

Slide 75 text

IDENTITY AVEC MONET UTILE❓ 75 — @MontpellierJug

Slide 76

Slide 76 text

IDENTITY AVEC MONET EX: CALCULS INTERMÉDIAIRES CF. /01-identity/projet.js 76 — @MontpellierJug

Slide 77

Slide 77 text

UN PEU PLUS LOIN ... 77 — @MontpellierJug

Slide 78

Slide 78 text

GESTION DES ! 78 — @MontpellierJug

Slide 79

Slide 79 text

NULL & UNDEFINED pain points 79 — @MontpellierJug

Slide 80

Slide 80 text

80 — @MontpellierJug

Slide 81

Slide 81 text

MAYBE AVEC MONET 81 — @MontpellierJug

Slide 82

Slide 82 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 82 — @MontpellierJug

Slide 83

Slide 83 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: '"' } ) 83 — @MontpellierJug

Slide 84

Slide 84 text

MAYBE AVEC MONET UTILE❓ 84 — @MontpellierJug

Slide 85

Slide 85 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)) } 85 — @MontpellierJug

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

MAYBE AVEC MONET CATAMORPHISME❓ 88 — @MontpellierJug

Slide 89

Slide 89 text

CATAMORPHISME❓ "In category theory, the concept of catamorphism denotes the unique homomorphism from an initial algebra into some other algebra." 89 — @MontpellierJug

Slide 90

Slide 90 text

CATAMORPHISME❓ "In category theory, the concept of catamorphism denotes the unique homomorphism from an initial algebra into some other algebra." ! 90 — @MontpellierJug

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

ET EN SCALA ❓ ! 92 — @MontpellierJug

Slide 93

Slide 93 text

OPTION == MAYBE val users: Array[Map[String, String]] = Array( Map("id" -> "panda", "avatar" -> "!"), Map("id" -> "fox", "avatar" -> """), Map("id" -> "lion", "avatar" -> "#") ) 93 — @MontpellierJug

Slide 94

Slide 94 text

find() ALWAYS RETURN AN Option users.find(user => user("id") == "panda") // Some(Map(id -> panda, avatar -> !)) users.find(user => user("id") == "tiger") // None 94 — @MontpellierJug

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

97 — @MontpellierJug

Slide 98

Slide 98 text

EITHER AVEC MONET 98 — @MontpellierJug

Slide 99

Slide 99 text

EITHER AVEC MONET UTILE❓ > DÉMO ⚠ RUN THE " SERVER > 03-either/either1.js > 03-either/either2.js 99 — @MontpellierJug

Slide 100

Slide 100 text

SERVER SIDE let users = [ {id:1, name:"bob", avatar:"!"} , {id:2, name:"sam", avatar:"""} , {id:3, name:"jane", avatar:"#"} , {id:4, name:"john", avatar:"$"} ] app.get('/users/:id', (req, res) => { let user = users.find(u => u.id == parseInt(req.params.id)) res.send(user !== undefined ? user : {}) }); 100 — @MontpellierJug

Slide 101

Slide 101 text

getUserById let getUserById = (id) => { return fetch(`http://localhost:9090/users/${id}`, { method: 'GET', headers: {"Content-Type": "application/json"}, }) .then(response => response.json()) .then(jsonData => jsonData) .catch(err => err) } 101 — @MontpellierJug

Slide 102

Slide 102 text

getUserById getUserById(1) .then( user => console.log(user) ).catch( err => console.log(err) ) 102 — @MontpellierJug

Slide 103

Slide 103 text

DEMO either1.js { FetchError: request to http://localhost:9090/users/1 failed, reason: connect ECONNREFUSED 127.0.0.1:9090 at ClientRequest. (/Users/k33g/Dropbox/k33g/fp/node_modules/node-fetch/index.js:133:11) at emitOne (events.js:96:13) at ClientRequest.emit (events.js:188:7) 103 — @MontpellierJug

Slide 104

Slide 104 text

getUserById ! let getUserById = (id) => { return fetch(`http://localhost:9090/users/${id}`, { method: 'GET', headers: {"Content-Type": "application/json"}, }).then(response => response.json()) .then(user => { if(user.id === undefined) { ! return monet.Either.Left("" User unknown"); } ! return monet.Either.Right(user); }) ! .catch(err => monet.Either.Left(`" ${err.message}`)) } 104 — @MontpellierJug

Slide 105

Slide 105 text

getUserById ! getUserById(1).then( result => { result.isRight() ? console.log(result.right()) // { id: 1, name: 'bob', avatar: '!' } : console.log(result.left()) // " User unknown }) 105 — @MontpellierJug

Slide 106

Slide 106 text

getUserById ! map() cata() " ... getUserById(1).then(result => { result ! .map(user => user.avatar) ! .cata( left => console.log(left), // " right => console.log(right) // # ) }) 106 — @MontpellierJug

Slide 107

Slide 107 text

ET EN SCALA ❓ !! 107 — @MontpellierJug

Slide 108

Slide 108 text

EITHER def getUserById(id: Int): Either[String, Any] = { try { // OK, there is something more "stylish" val userOption = JSON.parseFull(fromURL("http://localhost:9090/users/"+id.toString).mkString) // JSON.parseFull returns an Option ! userOption match { " case None => Left("# Bad Json") case Some(user) => { user.asInstanceOf[Map[String, Any]].get("id") match { " case None => Left("# User unknown") " case Some(value) => Right(user) }}} } catch { " case e: Exception => Left("# " + e.toString) } } 108 — @MontpellierJug

Slide 109

Slide 109 text

EITHER (UTILISATION) getUserById(1) match { case Left(errMess) => println(errMess) case Right(user) => println(user) } 109 — @MontpellierJug

Slide 110

Slide 110 text

MORE "STYLISH" WITH Try ❤ def getUserById(id: Int): Either[String, Any] = { Try( JSON.parseFull(fromURL("http://localhost:9090/users/"+id.toString).mkString) ) match { ! case Failure(fail) => Left("" " + fail.toString) ! case Success(userOption) => { userOption match { ! case None => Left("" Bad Json") case Some(user) => { user.asInstanceOf[Map[String, Any]].get("id") match { ! case None => Left("" User unknown") ! case Some(value) => Right(user) }}}}} } 110 — @MontpellierJug

Slide 111

Slide 111 text

111 — @MontpellierJug

Slide 112

Slide 112 text

VALIDATION AVEC MONET 112 — @MontpellierJug

Slide 113

Slide 113 text

VALIDATION AVEC MONET - ! PAS UNE MONAD(E)❗ Validation is not quite a monad as it doesn’t quite follow the monad rules, even though it has the monad methods. It that can hold either a success value or a failure value (i.e. an error message or some other failure object) and has methods for accumulating errors. -- Monet - la doc 113 — @MontpellierJug

Slide 114

Slide 114 text

VALIDATION: SUCCESS AND FAIL let success = monet.Validation.success("You won❗ ""); // { val: 'You won❗ "', isSuccessValue: true } let failure = monet.Validation.fail("You lost❗ #"); // { val: 'You lost❗ #', isSuccessValue: false } 114 — @MontpellierJug

Slide 115

Slide 115 text

getUserById ! let getUserById = (id) => { return fetch(`http://localhost:9090/users/${id}`, { method: 'GET', headers: {"Content-Type": "application/json"}, }) .then(response => response.json()) .then(user => { if(user.id === undefined) { ! return monet.Validation.fail("" User unknown"); } ! return monet.Validation.success(user); }) ! .catch(err => monet.Validation.fail(`" ${err.message}`)) } 115 — @MontpellierJug

Slide 116

Slide 116 text

getUserById ! map() cata() " ... getUserById(1).then(result => { result.map(user => user.avatar).cata( failure => console.log(failure), success => console.log(success) ) }) 116 — @MontpellierJug

Slide 117

Slide 117 text

! ⁉ 117 — @MontpellierJug

Slide 118

Slide 118 text

APPLICATIVE FUNCTOR PATTERN ! Implements the applicative functor pattern. ap will apply a function over the validation from within the supplied validation. If any of the validations are fails then the function will collect the errors. -- Monet - la doc 118 — @MontpellierJug

Slide 119

Slide 119 text

VALIDER PLUSIEURS POINTS ET COLLECTER LES ERREURS let users = [ {id:1, name:"bob", avatar:"!"} , {id:2, name:"sam", avatar:"""} , {id:3, name:"jane", avatar:"#"} , {id:4, name:"john", avatar:"$"} , {id:5, name:"paul"} , {id:6, avatar:"%"} , {id:7} ] app.get('/users/:id', (req, res) => { let user = users.find(u => u.id == parseInt(req.params.id)) res.send(user !== undefined ? user : {}) }); 119 — @MontpellierJug

Slide 120

Slide 120 text

"VALIDATORS" QUI RETOURNENT DES VALIDATIONS let isNotUndefined = user => { return user.id !== undefined ? monet.Validation.success(user.id) : monet.Validation.fail(["! User unknown"]); // " have you seen the []? } 120 — @MontpellierJug

Slide 121

Slide 121 text

"VALIDATORS" let hasName = user => { return user.name !== undefined ? monet.Validation.success(user.name) : monet.Validation.fail(["! No name ❗"]); } 121 — @MontpellierJug

Slide 122

Slide 122 text

"VALIDATORS" let hasAvatar = user => { return user.avatar !== undefined ? monet.Validation.success(user.avatar) : monet.Validation.fail(["! No avatar ❗"]); } 122 — @MontpellierJug

Slide 123

Slide 123 text

"LA FONCTION DU SUCCÈS" let onSuccessfulValidation = (id) => (name) => (avatar) => { return {id, name, avatar} } 123 — @MontpellierJug

Slide 124

Slide 124 text

getUserById ! let getUserById = (id) => { return fetch(`http://localhost:9090/users/${id}`, { method: 'GET', headers: {"Content-Type": "application/json"}, }) .then(response => response.json()) .then(user => ! isNotUndefined(user) ! .ap(hasName(user) ! .ap(hasAvatar(user) ! .map(onSuccessfulValidation))) ) .catch(err => monet.Validation.fail(`" ${err.message}`)) } 124 — @MontpellierJug

Slide 125

Slide 125 text

getUserById ! cata() " ... getUserById(1).then(result => { result.cata( errors => console.error("Errors:", errors), value => console.info("Success:", value) ) }) // Success: { id: '!', name: 'bob', avatar: 1 } 125 — @MontpellierJug

Slide 126

Slide 126 text

getUserById ! cata() " ... getUserById(7).then(result => { result.cata( errors => console.error("Errors:", errors), value => console.info("Success:", value) ) }) // Errors: [ '! No name ❗', '# No avatar ❗' ] 126 — @MontpellierJug

Slide 127

Slide 127 text

ET EN SCALA ❓ !!! 127 — @MontpellierJug

Slide 128

Slide 128 text

J'AI PAS EU LE COURAGE ! MAIS IL Y A DES LIBRAIRIES POUR ÇA > scalaz > cats 128 — @MontpellierJug

Slide 129

Slide 129 text

SINON AVEC LES UNIONS TYPES ÇA SERAIT FACILE À CODER... > Dotty (http://dotty.epfl.ch/) > scalaz > Incantations ... 129 — @MontpellierJug

Slide 130

Slide 130 text

INCANTATIONS ! type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (T ∨ U) } def size[T: (Int |∨| String)#λ](t: T) = t match { case i: Int => i case s: String => s.length } 130 — @MontpellierJug

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

UNION TYPES ❓ ! 132 — @MontpellierJug

Slide 133

Slide 133 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 ! 133 — @MontpellierJug

Slide 134

Slide 134 text

EN GOLO ÇA DONNERAIT CECI: union SomeThing = { Yum = { value } # it's good Yuck = { value } # it's bad } let banana = SomeThing.Yum("!") let hotPepper = SomeThing.Yuck(""") # you can do that: println(banana: isYum()) # true println(hotPepper: isYuck()) # true 134 — @MontpellierJug

Slide 135

Slide 135 text

... ON PIMP LES SOUS-TYPES: CATAMORPHISME augment SomeThing$Yum { function cata = |this, ifYuck, ifYum| -> ifYum(this: value()) } augment SomeThing$Yuck { function cata = |this, ifYuck, ifYum| -> ifYuck(this: value()) } 135 — @MontpellierJug

Slide 136

Slide 136 text

CATAMORPHISME SomeThing.Yuck("!"): cata( |value| -> println("I " " + value), |value| -> println("I # " + value) ) SomeThing.Yum("$"): cata( |value| -> println("I " " + value), |value| -> println("I # " + value) ) 136 — @MontpellierJug

Slide 137

Slide 137 text

ON PIMP ENCORE YUM augment SomeThing$Yum { function cata = |this, ifYuck, ifYum| -> ifYum(this: value()) function map = |this, fn| -> this.Yum(fn(this: value())) function ap = |this, something| -> something: cata( |errors| -> something , |value| -> something: map(this: value()) ) } 137 — @MontpellierJug

Slide 138

Slide 138 text

ON PIMP ENCORE YUCK augment SomeThing$Yuck { function cata = |this, ifYuck, ifYum| -> ifYuck(this: value()) function map = |this, fn| -> this function ap = |this, something| -> something: cata( |errors| { errors: addAll(something: value(): clone()) return this.Yuck(errors) }, |value| -> this ) } 138 — @MontpellierJug

Slide 139

Slide 139 text

VALIDATION ! " 139 — @MontpellierJug

Slide 140

Slide 140 text

VALIDATORS let checkMonth = |monthNumber| { if (monthNumber <=12 and monthNumber >0) { return SomeThing.Yum(monthNumber) } else { return SomeThing.Yuck(vector["bad month number"]) } } let checkDay = |dayNumber| { if (dayNumber <=7 and dayNumber >0 ) { return SomeThing.Yum(dayNumber) } else { return SomeThing.Yuck(vector["bad day number"]) } } 140 — @MontpellierJug

Slide 141

Slide 141 text

VALIDATION ! " SomeThing.Yum( |day| -> |month| -> "Day:" + day + " Month:" + month ) : ap(checkDay(42)) : ap(checkMonth(42)) : cata( |err| -> println("!: " + err), |value| -> println("": " + value) ) # !: [bad month number, bad month number] # ": Day:2 Month:5 141 — @MontpellierJug

Slide 142

Slide 142 text

UNION TYPES EN JAVASCRIPT 142 — @MontpellierJug

Slide 143

Slide 143 text

UNION-TYPE.JS❓ https://github.com/paldepind/union-type 143 — @MontpellierJug

Slide 144

Slide 144 text

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

Slide 145

Slide 145 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) } }) 145 — @MontpellierJug

Slide 146

Slide 146 text

C'EST POUR ÇA QUE J❤ LE JAVASCRIPT Tout est possible simplement 146 — @MontpellierJug

Slide 147

Slide 147 text

BTW Scala c'est simple comme du JS finalement ! " 147 — @MontpellierJug

Slide 148

Slide 148 text

QUELQUES RESSOURCES 148 — @MontpellierJug

Slide 149

Slide 149 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 149 — @MontpellierJug

Slide 150

Slide 150 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 150 — @MontpellierJug

Slide 151

Slide 151 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/ 151 — @MontpellierJug

Slide 152

Slide 152 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 152 — @MontpellierJug

Slide 153

Slide 153 text

PERSPECTIVES RX 153 — @MontpellierJug

Slide 154

Slide 154 text

REMERCIEMENTS Vous Montpellier JUG @loic_d, @jponge, @clementd, @yannick_loiseau, @titimoby Etienne Issartial & Thomas Guenoux 154 — @MontpellierJug

Slide 155

Slide 155 text

155 — @MontpellierJug