Slide 1

Slide 1 text

Programação Funcional com JavaScript_

Slide 2

Slide 2 text

Conteúdo ● First Class Functions ● Pure Functions ● Currying ● Compose ● Pointfree ● Hindley-Milner type system ● Functors ● Monadic Onions ● Applicative Functors

Slide 3

Slide 3 text

Aprendendo a dirigir

Slide 4

Slide 4 text

Segundo carro

Slide 5

Slide 5 text

Spaceship

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Caminho sem volta

Slide 9

Slide 9 text

DRY Don't Repeat Yourself

Slide 10

Slide 10 text

YAGNI You Ain't Gonna Need It

Slide 11

Slide 11 text

Loose Coupling, High Cohesion

Slide 12

Slide 12 text

POLA Principle Of Least Astonishment

Slide 13

Slide 13 text

KISS Keep it simple, stupid!

Slide 14

Slide 14 text

Single Responsibility

Slide 15

Slide 15 text

blá blá blá...

Slide 16

Slide 16 text

Exemplo \o/

Slide 17

Slide 17 text

// imperative var makes = []; for (var i = 0; i < cars.length; i++) { makes.push(cars[i].make); } // declarative var makes = cars.map(function(car) { return car.make; });

Slide 18

Slide 18 text

Mas, JavaScript não é orientado a objetos?

Slide 19

Slide 19 text

var Rebanho = function(n) { this.gaivotas = n; }; Rebanho.prototype.unir = function(outro) { this.gaivotas += outro.gaivotas; return this; }; Rebanho.prototype.procriar = function(outro) { this.gaivotas = this.gaivotas * outro.gaivotas; return this; }; var rebanho_a = new Rebanho(4); var rebanho_b = new Rebanho(2); var rebanho_c = new Rebanho(0); var result = rebanho_a.unir(rebanho_c) .procriar(rebanho_b).unir(rebanho_a.procriar(rebanho_b)).gaivotas; Orientado a Objetos

Slide 20

Slide 20 text

var unir = function(rebanho_x, rebanho_y) { return rebanho_x + rebanho_y; }; var procriar = function(rebanho_x, rebanho_y) { return rebanho_x * rebanho_y; }; var rebanho_a = 4; var rebanho_b = 2; var rebanho_c = 0; var result = unir( procriar(rebanho_b, unir(rebanho_a, rebanho_c)), procriar(rebanho_a, rebanho_b) ); //=> 16 Programação Funcional

Slide 21

Slide 21 text

var add = function(x, y) { return x + y; }; var multiply = function(x, y) { return x * y; }; var rebanho_a = 4; var rebanho_b = 2; var rebanho_c = 0; var result = add( multiply(rebanho_b, add(rebanho_a, rebanho_c)), multiply(rebanho_a, rebanho_b) ); //=> 16 Programação Funcional

Slide 22

Slide 22 text

Leis Matemáticas Comutativa, Associativa, Distributiva e Identidade

Slide 23

Slide 23 text

Comutatividade a ordem dos fatores não altera o produto // x + y = y + x add(x, y) === add(y, x); // x * y = y * x multiply(x, y) === multiply(y, x);

Slide 24

Slide 24 text

Associatividade // (x + y) + z = x + (y + z) add(add(x, y), z) === add(x, add(y, z)); // (x * y) * z = x * (y * z) multiply(multiply(x, y), z) === multiply(x, multiply(y, z));

Slide 25

Slide 25 text

Identidade // x + 0 = x add(x, 0) === x;

Slide 26

Slide 26 text

Distributividade // a × (b + c) = a × b + a × c multiply(x, add(y,z)) === add(multiply(x, y), multiply(x, z));

Slide 27

Slide 27 text

Aplicando as leis matemáticas em nosso código.

Slide 28

Slide 28 text

// Original line add(multiply(flock_b, add(flock_a, flock_c)), multiply(flock_a, flock_b)); // (add(flock_a, flock_c) == flock_a) add(multiply(flock_b, flock_a), multiply(flock_a, flock_b)); #1 passo: aplicar a lei da identidade (x + 0) = x

Slide 29

Slide 29 text

add(multiply(flock_b, flock_a), multiply(flock_a, flock_b)); multiply(flock_b, add(flock_a, flock_a)); #2 passo: aplicar a lei da distributividade a × (b + c) = a × b + a × c

Slide 30

Slide 30 text

// Original line add(multiply(flock_b, add(flock_a, flock_c)), multiply(flock_a, flock_b)); // Apply the identity property to remove the extra add // (add(flock_a, flock_c) == flock_a) add(multiply(flock_b, flock_a), multiply(flock_a, flock_b)); // Apply distributive property to achieve our result multiply(flock_b, add(flock_a, flock_a));

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

First Class Functions

Slide 33

Slide 33 text

var hi = function(name) { return 'Hi ' + name; }; var greeting = function(name) { return hi(name); };

Slide 34

Slide 34 text

var greeting = hi; greeting('JSday'); // "Hi JSday”

Slide 35

Slide 35 text

var getServerStuff = function(callback) { return ajaxCall(function(json) { return callback(json); }); }; // or var getServerStuff = ajaxCall;

Slide 36

Slide 36 text

var getServerStuff = function(callback) { return ajaxCall(function(json) { return callback(json); }); }; // or var getServerStuff = ajaxCall; return ajaxCall(callback);

Slide 37

Slide 37 text

var getServerStuff = function(callback) { return callback(json); }; // or var getServerStuff = ajaxCall;

Slide 38

Slide 38 text

var BlogController = (function() { var index = function(posts) { return Views.index(posts); }; var show = function(post) { return Views.show(post); }; var create = function(attrs) { return Db.create(attrs); }; var update = function(post, attrs) { return Db.update(post, attrs); }; var destroy = function(post) { return Db.destroy(post); }; return { index: index, show: show, create: create, update: update, destroy: destroy, }; })(); var BlogController = { index: Views.index, show: Views.show, create: Db.create, update: Db.update, destroy: Db.destroy, };

Slide 39

Slide 39 text

Por que devo favorecer a "primeira classe"?

Slide 40

Slide 40 text

httpGet('/post/2', function(json) { return renderPost(json); }); httpGet('/post/2', function(json, err) { return renderPost(json, err); });

Slide 41

Slide 41 text

httpGet('/post/2', renderPost); httpGet('/post/2', function(json) { return renderPost(json); });

Slide 42

Slide 42 text

Higher-Order Functions

Slide 43

Slide 43 text

Tente sempre fazer da maneira mais genérica e concisa.

Slide 44

Slide 44 text

// específico do nosso blog var validArticles = function(articles) { return articles.filter(function(article) { return article !== null && article !== undefined; }); }; // reutilizável para futuros projetos var compact = function(xs) { return xs.filter(function(x) { return x !== null && x !== undefined; }); };

Slide 45

Slide 45 text

As funções dos objetos também são de primeira classe?

Slide 46

Slide 46 text

var Pokemon = function(name) { this.name = name; return this; }; Pokemon.prototype.speak = function() { return this.name; }; var pikachu = new Pokemon('Pikachú'); var speak = pikachu.speak; speak(); //=> undefined

Slide 47

Slide 47 text

var Pokemon = function(name) { this.name = name; return this; }; Pokemon.prototype.speak = function() { return this.name; }; var pikachu = new Pokemon('Pikachú'); var speak = pikachu.speak.bind(pikachu); speak(); //=> Pikachú

Slide 48

Slide 48 text

Pure Functions É uma função que, dado o mesmo input, sempre retorna o mesmo output e não provoca side effects.

Slide 49

Slide 49 text

Exemplos \o/

Slide 50

Slide 50 text

Slice vs Splice var xs = [1, 2, 3, 4, 5]; // pure xs.slice(0, 3); //=> [1, 2, 3] xs.slice(0, 3); //=> [1, 2, 3] xs.slice(0, 3); //=> [1, 2, 3] var xs = [1, 2, 3, 4, 5]; // impure xs.splice(0, 3); //=> [1, 2, 3] xs.splice(0, 3); //=> [4, 5] xs.splice(0, 3); //=> []

Slide 51

Slide 51 text

// impure var minimum = 21; var checkAge = function(age) { return age >= minimum; }; // pure var checkAge = function(age) { var minimum = 21; return age >= minimum; };

Slide 52

Slide 52 text

var immutableState = Object.freeze({ minimum: 21, }); Objeto Imutável

Slide 53

Slide 53 text

Side Effects A side effect is a change of system state or observable interaction with the outside world that occurs during the calculation of a result.

Slide 54

Slide 54 text

Alguns side effects... ● mudança no sistema de arquivos ● inserção de registro no banco de dados ● fazer uma chamada HTTP ● mutations ● imprimir alguma informação na tela / logging ● obtenção de input do usuário ● querying o DOM (querySelector)

Slide 55

Slide 55 text

Relembrando a Matemática Básica

Slide 56

Slide 56 text

O que é uma função? A function is a special relationship between values: Each of its input values gives back exactly one output value. ~> mathfun.com

Slide 57

Slide 57 text

● It must work for every possible input value; ● And it has only one relationship for each input value; Relacionamento tem regras

Slide 58

Slide 58 text

Exemplo: uma relação x => x ^ 2

Slide 59

Slide 59 text

Input Output 1 1 2 4 3 9 4 16 5 25 6 36 Exemplo: uma relação x => x ^ 2

Slide 60

Slide 60 text

Exemplo: uma relação x => x ^ 2

Slide 61

Slide 61 text

Esse relacionamento NÃO é uma função!

Slide 62

Slide 62 text

(One-to-many) (Many-to-one) Relacionamento: input vs output

Slide 63

Slide 63 text

var toLowerCase = { 'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd', 'E': 'e', 'F': 'f', }; toLowerCase['C']; //=> 'c' Usando [ ] ao invés de ( ), ainda é uma função? var isPrime = { 1: false, 2: true, 3: true, 4: false, 5: true, 6: false, }; isPrime[3]; //=> true

Slide 64

Slide 64 text

E as funções com múltiplos argumentos?

Slide 65

Slide 65 text

Vantagens da Puridade

Slide 66

Slide 66 text

#1 Cacheable

Slide 67

Slide 67 text

var squareNumber = memoize(function(x) { return x * x; }); squareNumber(4); //=> 16 squareNumber(4); // returns cache for input 4 //=> 16 squareNumber(5); //=> 25 squareNumber(5); // returns cache for input 5 //=> 25 Memoization

Slide 68

Slide 68 text

var memoize = function(f) { var cache = {}; return function() { var arg_str = JSON.stringify(arguments); cache[arg_str] = cache[arg_str] || f.apply(f, arguments); return cache[arg_str]; }; } Exemplo: Memoize function

Slide 69

Slide 69 text

var pureHttpCall = memoize(function(url, params) { return function() { return $.getJSON(url, params); }; }); "Cacheando" funções

Slide 70

Slide 70 text

#2 Portable / Self-Documenting

Slide 71

Slide 71 text

//impure var signUp = function(attrs) { var user = saveUser(attrs); welcomeUser(user); }; var saveUser = function(attrs) { var user = Db.save(attrs); ... }; var welcomeUser = function(user) { Email(user, ...); ... }; //pure var signUp = function(Db, Email, attrs) { return function() { var user = saveUser(Db, attrs); welcomeUser(Email, user); }; }; var saveUser = function(Db, attrs) { ... }; var welcomeUser = function(Email, user) { ... };

Slide 72

Slide 72 text

"The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana... and the entire jungle" ~> Erlang creator, Joe Armstrong

Slide 73

Slide 73 text

#3 Testable

Slide 74

Slide 74 text

#4 Reasonable

Slide 75

Slide 75 text

#5 Parallel Code

Slide 76

Slide 76 text

Why I need to freeze an object in javascript? http://stackoverflow.com/questions/14791302/why-would- i-need-to-freeze-an-object-in-javascript

Slide 77

Slide 77 text

Can functions have multiples arguments? http://math.stackexchange.com/questions/926249/can-fun ctions-have-multiple-inputs

Slide 78

Slide 78 text

Currying

Slide 79

Slide 79 text

var add = function(x) { return function(y) { return x + y; }; }; var increment = add(1); var addTen = add(10); increment(2); // 3 addTen(2); // 12

Slide 80

Slide 80 text

var curry = require('lodash/curry'); var match = curry(function(what, str) { return str.match(what); }); match(/\s+/g, 'hello world'); // [ ' ' ] var hasSpaces = match(/\s+/g); // function(x) { return x.match(/\s+/g) } hasSpaces('hello world'); // [ ' ' ] hasSpaces('spaceless'); // null

Slide 81

Slide 81 text

var hasSpaces = match(/\s+/g); var filter = curry(function(f, ary) { return ary.filter(f); }); filter(hasSpaces, ['tori_spelling', 'tori amos']); // ['tori amos'] var findSpaces = filter(hasSpaces); findSpaces(['tori_spelling', 'tori amos']); // ['tori amos']

Slide 82

Slide 82 text

Exercício Crie uma função que substitui todas as vogais de um texto por "asterisco" usando currying. Dica: str.replace(/[aeiou]/ig, '*');

Slide 83

Slide 83 text

Exercício https://github.com/jonataa/course-fp-js/blob/master/exercise s/currying.md

Slide 84

Slide 84 text

Composing

Slide 85

Slide 85 text

var compose = function(f, g) { return function(x) { return f(g(x)); }; }; Representação matemática: (f º g)(x)

Slide 86

Slide 86 text

var toUpperCase = function(x) { return x.toUpperCase(); }; var exclaim = function(x) { return x + '!'; }; var shout = compose(exclaim, toUpperCase); shout("send in the clowns"); //=> "SEND IN THE CLOWNS!"

Slide 87

Slide 87 text

// without compose var shout = function(x) { return exclaim(toUpperCase(x)); }; // with compose var shout = compose(exclaim, toUpperCase); shout("send in the clowns"); //=> "SEND IN THE CLOWNS!"

Slide 88

Slide 88 text

var head = function(x) { return x[0]; }; var reverse = reduce(function(acc, x) { return [x].concat(acc); }, []); var last = compose(head, reverse); last(['jumpkick', 'roundhouse', 'uppercut']); //=> 'uppercut'

Slide 89

Slide 89 text

compose(f, compose(g, h)) == compose(compose(f, g), h) // true

Slide 90

Slide 90 text

compose(toUpperCase, compose(head, reverse)); // or compose(compose(toUpperCase, head), reverse);

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

var g = function(x) { return x.length; }; var f = function(x) { return x === 4; }; var isFourLetterWord = compose(f, g);

Slide 93

Slide 93 text

var lastUpper = compose(toUpperCase, head, reverse); lastUpper(['jumpkick', 'roundhouse', 'uppercut']); //=> 'UPPERCUT' var loudLastUpper = compose(exclaim, toUpperCase, head, reverse); loudLastUpper(['jumpkick', 'roundhouse', 'uppercut']); //=> 'UPPERCUT!'

Slide 94

Slide 94 text

var loudLastUpper = compose(exclaim, toUpperCase, head, reverse); // ou var last = compose(head, reverse); var loudLastUpper = compose(exclaim, toUpperCase, last); // ou var last = compose(head, reverse); var angry = compose(exclaim, toUpperCase); var loudLastUpper = compose(angry, last); // n possibilidades...

Slide 95

Slide 95 text

Exercício https://github.com/jonataa/course-fp-js/blob/master/exercise s/composing.md

Slide 96

Slide 96 text

Pointfree

Slide 97

Slide 97 text

//não é pointfree pq mencionou o dado: word var snakeCase = function(word) { return word.toLowerCase().replace(/\s+/ig, '_'); }; //pointfree var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);

Slide 98

Slide 98 text

//not pointfree because we mention the data: name var initials = function(name) { return name.split(' ').map(compose(toUpperCase, head)).join('. '); }; //pointfree var initials = compose(join('. '), map(compose(toUpperCase, head)), split(' ')); initials("hunter stockton thompson"); // 'H. S. T'

Slide 99

Slide 99 text

Debugging compose functions

Slide 100

Slide 100 text

var latin = compose(map, angry, reverse); latin(['frog', 'eyes']); // error // right - each function expects 1 argument. var latin = compose(map(angry), reverse); latin(['frog', 'eyes']); // ['EYES!', 'FROG!'])

Slide 101

Slide 101 text

Impure trace function

Slide 102

Slide 102 text

var trace = curry(function(tag, x) { console.log(tag, x); return x; }); var dasherize = compose(join('-'), toLower, split(' '), replace(/\s{2,}/ig, ' ')); dasherize('The world is a vampire'); // TypeError: Cannot read property 'apply' of undefined

Slide 103

Slide 103 text

var dasherize = compose(join('-'), toLower, trace('after split'), split(' '), replace(/\s{2,}/ig, ' ')); // after split [ 'The', 'world', 'is', 'a', 'vampire' ] Debugging...

Slide 104

Slide 104 text

var dasherize = compose(join('-'), map(toLower), split(' '), replace(/\s{2,}/ig, ' ')); dasherize('The world is a vampire'); // 'the-world-is-a-vampire' Ah, preciso mapear o "toLower".

Slide 105

Slide 105 text

Declarative Coding

Slide 106

Slide 106 text

// imperative var authenticate = function(form) { var user = toUser(form); return logIn(user); }; // declarative var authenticate = compose(logIn, toUser);

Slide 107

Slide 107 text

A Flickr of functional programming

Slide 108

Slide 108 text

Slide 109

Slide 109 text

requirejs.config({ paths: { ramda: 'https://cdnjs.cloudflare.com/ajax/libs/ramda/0.13.0/ramda.min', jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min' }, }); require([ 'ramda', 'jquery', ], function(_, $) { var trace = _.curry(function(tag, x) { console.log(tag, x); return x; }); // app goes here });

Slide 110

Slide 110 text

Especificações do nosso app: 1. Construir uma URL a partir da palavra-chave; 2. Fazer uma chamada HTTP à API do Flickr; 3. Transformar o resultado JSON em HTML images; 4. Renderiza-los na tela; https://api.flickr.com/services/feeds/photos_public.gne?tags =cats&format=json&jsoncallback=?

Slide 111

Slide 111 text

var Impure = { getJSON: _.curry(function(callback, url) { $.getJSON(url, callback); }), setHtml: _.curry(function(sel, html) { $(sel).html(html); }) }; Separar as funções "impuras"

Slide 112

Slide 112 text

Hindley-Milner

Slide 113

Slide 113 text

// capitalize :: String -> String var capitalize = function(s) { return toUpperCase(head(s)) + toLowerCase(tail(s)); } capitalize("smurf"); //=> "Smurf"

Slide 114

Slide 114 text

// join :: String -> [String] -> String var join = curry(function(what, xs) { return xs.join(what); }); // match :: Regex -> String -> [String] var match = curry(function(reg, s) { return s.match(reg); });

Slide 115

Slide 115 text

// match :: Regex -> String -> [String] var match = curry(function(reg, s) { return s.match(reg); }); // replace :: Regex -> String -> String -> String var replace = curry(function(reg, sub, s) { return s.replace(reg, sub); });

Slide 116

Slide 116 text

Sinta-se livre para agrupá-los com ( ) // match :: Regex -> (String -> [String]) var match = curry(function(reg, s) { return s.match(reg); });

Slide 117

Slide 117 text

// match :: Regex -> (String -> [String]) // onHoliday :: String -> [String] var onHoliday = match(/holiday/ig);

Slide 118

Slide 118 text

// head :: [a] -> a var head = function(xs) { return xs[0]; }; // filter :: (a -> Bool) -> [a] -> [a] var filter = curry(function(f, xs) { return xs.filter(f); }); // reduce :: (b -> a -> b) -> b -> [a] -> b var reduce = curry(function(f, x, xs) { return xs.reduce(f, x); });

Slide 119

Slide 119 text

https://www.haskell.org/hoogle/

Slide 120

Slide 120 text

// sort :: Ord a => [a] -> [a] // assertEqual :: (Eq a, Show a) => a -> a -> Assertion Constraints

Slide 121

Slide 121 text

Containers

Slide 122

Slide 122 text

var Container = function(x) { this.__value = x; } Container.of = function(x) { return new Container(x); };

Slide 123

Slide 123 text

Container.of(3); //=> Container(3) Container.of('hotdogs'); //=> Container("hotdogs") Container.of(Container.of({ name: 'yoda', })); //=> Container(Container({name: "yoda" }))

Slide 124

Slide 124 text

// (a -> b) -> Container a -> Container b Container.prototype.map = function(f) { return Container.of(f(this.__value)); }

Slide 125

Slide 125 text

Container.of(2).map(function(two) { return two + 2; }); //=> Container(4)

Slide 126

Slide 126 text

Container.of("flamethrowers").map(function(s) { return s.toUpperCase(); }); //=> Container("FLAMETHROWERS")

Slide 127

Slide 127 text

Container.of("bombs") .map(_.concat(' away')) .map(_.prop('length')); //=> Container(10)

Slide 128

Slide 128 text

Functors A Functor is a type that implements map and obeys some laws

Slide 129

Slide 129 text

var Maybe = function(x) { this.__value = x; }; Maybe.of = function(x) { return new Maybe(x); }; Maybe.prototype.isNothing = function() { return (this.__value === null || this.__value === undefined); }; Maybe.prototype.map = function(f) { return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value)); };

Slide 130

Slide 130 text

var Maybe = function(x) { this.__value = x; }; Maybe.of = function(x) { return new Maybe(x); }; Maybe.prototype.isNothing = function() { return (this.__value === null || this.__value === undefined); }; Maybe.prototype.map = function(f) { return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value)); };

Slide 131

Slide 131 text

Maybe.of('Malkovich Malkovich').map(match(/a/ig)); //=> Maybe(['a', 'a']) Maybe.of(null).map(match(/a/ig)); //=> Maybe(null)

Slide 132

Slide 132 text

Maybe.of({ name: 'Boris', }).map(_.prop('age')).map(add(10)); //=> Maybe(null) Maybe.of({ name: 'Dinah', age: 14, }).map(_.prop('age')).map(add(10)); //=> Maybe(24)

Slide 133

Slide 133 text

E o pointfree?

Slide 134

Slide 134 text

// map :: Functor f => (a -> b) -> f a -> f b var map = curry(function(f, any_functor_at_all) { return any_functor_at_all.map(f); });

Slide 135

Slide 135 text

Caso de Uso Functors

Slide 136

Slide 136 text

// safeHead :: [a] -> Maybe(a) var safeHead = function(xs) { return Maybe.of(xs[0]); }; var streetName = compose(map(_.prop('street')), safeHead, _.prop('addresses')); streetName({ addresses: [], }); // Maybe(null) streetName({ addresses: [{ street: 'Shady Ln.', number: 4201, }], }); // Maybe("Shady Ln.")

Slide 137

Slide 137 text

// withdraw :: Number -> Account -> Maybe(Account) var withdraw = curry(function(amount, account) { return account.balance >= amount ? Maybe.of({ balance: account.balance - amount, }) : Maybe.of(null); }); // finishTransaction :: Account -> String var finishTransaction = compose(remainingBalance, updateLedger); // <- these composed functions are hypothetical, not implemented here... // getTwenty :: Account -> Maybe(String) var getTwenty = compose(map(finishTransaction), withdraw(20)); getTwenty({ balance: 200.00, }); // Maybe("Your balance is $180.00") getTwenty({ balance: 10.00, }); // Maybe(null)

Slide 138

Slide 138 text

// maybe :: b -> (a -> b) -> Maybe a -> b var maybe = curry(function(x, f, m) { return m.isNothing() ? x : f(m.__value); }); // getTwenty :: Account -> String var getTwenty = compose( maybe("You're broke!", finishTransaction), withdraw(20) ); getTwenty({ balance: 200.00, }); // "Your balance is $180.00" getTwenty({ balance: 10.00, }); // "You're broke!"

Slide 139

Slide 139 text

Pure Error Handling

Slide 140

Slide 140 text

var Left = function(x) { this.__value = x; }; Left.of = function(x) { return new Left(x); }; Left.prototype.map = function(f) { return this; }; var Right = function(x) { this.__value = x; }; Right.of = function(x) { return new Right(x); }; Right.prototype.map = function(f) { return Right.of(f(this.__value)); }

Slide 141

Slide 141 text

Right.of('rain').map(function(str) { return 'b' + str; }); // Right('brain') Left.of('rain').map(function(str) { return 'b' + str; }); // Left('rain') Right.of({ host: 'localhost', port: 80, }).map(_.prop('host')); // Right('localhost') Left.of('rolls eyes...').map(_.prop('host')); // Left('rolls eyes...')

Slide 142

Slide 142 text

Vamos para o mundo real

Slide 143

Slide 143 text

var moment = require('moment'); // getAge :: Date -> User -> Either(String, Number) var getAge = curry(function(now, user) { var birthdate = moment(user.birthdate, 'YYYY-MM-DD'); if (!birthdate.isValid()) return Left.of('Birth date could not be parsed'); return Right.of(now.diff(birthdate, 'years')); }); getAge(moment(), { birthdate: '2005-12-12', }); // Right(9) getAge(moment(), { birthdate: '20010704', }); // Left('Birth date could not be parsed')

Slide 144

Slide 144 text

// fortune :: Number -> String var fortune = compose(concat('If you survive, you will be '), add(1)); // zoltar :: User -> Either(String, _) var zoltar = compose(map(console.log), map(fortune), getAge(moment())); zoltar({ birthdate: '2005-12-12', }); // 'If you survive, you will be 10' // Right(undefined) zoltar({ birthdate: 'balloons!', }); // Left('Birth date could not be parsed')

Slide 145

Slide 145 text

// either :: (a -> c) -> (b -> c) -> Either a b -> c var either = curry(function(f, g, e) { switch (e.constructor) { case Left: return f(e.__value); case Right: return g(e.__value); } }); // zoltar :: User -> _ var zoltar = compose(console.log, either(id, fortune), getAge(moment())); zoltar({ birthdate: '2005-12-12', }); // "If you survive, you will be 10" // undefined zoltar({ birthdate: 'balloons!', }); // "Birth date could not be parsed" // undefined

Slide 146

Slide 146 text

E o que vem depois?

Slide 147

Slide 147 text

Próximos passos ● pointed functors; ● monoids; ● metaphors ● Coordination Motivation ● applicative functor ● etc...

Slide 148

Slide 148 text

https://drboolean.gitbooks.io/mostly-adequate-guide

Slide 149

Slide 149 text

http://webschool.io/jsfuncional/

Slide 150

Slide 150 text

Referências https://github.com/MostlyAdequate/mostly-adequate-guide http://www.artima.com/weblogs/viewpost.jsp?thread=331531 http://math.stackexchange.com/questions/926249/can-functions-have-multiple-inp uts https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-1 -1f15e387e536#.csgxaemrn https://github.com/fantasyland/fantasy-land#functor https://en.wikipedia.org/wiki/Lambda_calculus https://github.com/ramda/ramda/wiki/Type-Signatures https://pt.wikipedia.org/wiki/Functor

Slide 151

Slide 151 text

Obrigado! [email protected] @JonataWeber