23.03.2017 - Graffiti HUB
Giulio Collesei
Front end dev @AQuest
Scrivere applicazioni utilizzando funzioni
f Main()
f A()
f B()
f A1()
f A2()
f A3()
f A4()
// Function declaration
function sayHello(name) {
return `Hello, ${name}`
}
// Function expression
const sayHello = name => `Hello, ${name}`
const putInPot = i1 => console.log(`${i1} in pot!`);
const cook = (i1, i2, f) => {
console.log(`Cooking ${i1} and ${i2}`);
f(i1);
f(i2);
};
cook('chicken', 'potatoes', putInPot);
// -> Cooking chicken and potatoes
// -> chicken in pot!
// -> potatoes in pot!
const getSecret = (secret) =>
() => console.log(secret);
const mySecret = getSecret('my secret');
mySecret();
// -> my secret
const PI = 3.14;
// Non-pure function
const calculateArea = (radius) =>
radius * radius * PI;
// Pure function
const calculateArea = (radius, PI) =>
radius * radius * PI;
Nella programmazione funzionale non c'è più il concetto di variabile. I dati non cambiano nel tempo.
// Non-immutable data
let myString = 'Hello';
myString = myString.concat(' world!');
// Immutable data
const myString = 'Hello';
const myString2 = myString.concat(' world!');
f(x) = x * x
f(x) = x * x
f(4) = 16
f(x) = x * x
f(4) = 16
f(4) = 16
f(4) = 16
f(x) = x * x
g(x) = f(x) + x
f(x) = x * x
g(x) = f(x) + x
g(4) = f(4) + 4
f(x) = x * x
g(x) = f(x) + x
g(4) = f(4) + 4
g(4) = 16 + 4
La referential transparency ci da la possibilità di cambiare un espressione con il suo risultato senza compromettere il funzionamento dell'applicazione.
Pure function
+ Immutable data
= Referential transparancy
Benefits
Nella programmazione funzionale le funzioni sono:
const a = [1,2,3,4,5];
// Imperative (how)
let b = 0;
for (let i = 0; i < a.length; i++) {
b = b + a[i];
}
// Declarative (what)
const sum = (b, a) => b + a;
const b = a.reduce(sum, 0);
Higher-order function
Funzioni che accettano come parametro altre funzioni e/o restituisco nuove funzioni
Array.prototype
.filter() .map() .reduce() .reduceRight() .find() .every() .concat()
Composizione di funzioni
È l'applicazione di una funzione al risultato di un'altra
A
B
B
C
C
D
D
Res.
func1()
func2()
func3()
Composizione di funzioni
È l'applicazione di una funzione al risultato di un'altra
f ∘ g (f dopo g)
Composizione di funzioni
È l'applicazione di una funzione al risultato di un'altra
f ∘ g (f dopo g)
(f ∘ g)(x)
Composizione di funzioni
È l'applicazione di una funzione al risultato di un'altra
f ∘ g (f dopo g)
(f ∘ g)(x)
f(g(x)) = y
Composizione di funzioni
È l'applicazione di una funzione al risultato di un'altra
// two functions that we'll compose
const applyTax = x => x * 1.08;
const applyShipping = x => x + 10;
const totalCost = compose(applyShipping, applyTax);
Applicazione parziale di funzione
L'applicazione di una funzione a una parte dei suoi argomenti
f(a, b) = c
Applicazione parziale di funzione
L'applicazione di una funzione a una parte dei suoi argomenti
f(a, b) = c
(f1(a))(b)
Applicazione parziale di funzione
L'applicazione di una funzione a una parte dei suoi argomenti
f(a, b) = c
(f1(a))(b) = f(a, b) = c
// Partial application
const f = (a, b, c) => a * b * c;
const g = partialApplication(f, [2, 3]);
// ...
const h = g(4); // 24
È un paradigma di programmazione che mira alla gestione di flussi di dati asincroni (stream) basati su eventi.
Gli stream sono simili agli array, solo asincroni.
Array
[1, 2, 3]
Stram
[1, ..... 2, ...... 3]
Una serie di eventi ordinati nel tempo
Una serie di eventi ordinati nel tempo
Tempo
e
e
e
a = b + c
(memory leaks)
(callback hell)
(cannot be cancelled)
Tempo
// tieni i pari
1
2
3
4
Tempo
filter() // tieni i pari
1
2
3
4
2
4
// fai il quadrato
Tempo
filter() // tieni i pari
1
2
3
4
2
4
map() // fai il quadrato
4
16
// riduci con somma
Tempo
filter() // tieni i pari
1
2
3
4
2
4
map() // fai il quadrato
4
16
reduce() // riduci con somma
4
20
KeyPress
KeyPress
+
Mouse move
merge()
Mouse move
http://reactivex.io/languages.html
Observable
È il wrapper dello stream.
Un Observable ha 3 eventi:
- Next
- Error
- Complete
var source = Rx.Observable.range(0, 3);
Observable
Observables are lazy-evaluated
Observer
L'oggetto passato al metodo .subscribe() che contiente le 3 callback
var source = Rx.Observable.range(0, 3);
source.subscribe({
next: x => console.log(`Next: ${x}`),
error: err => console.error(`Error: ${err}`),
complete: () => console.log(`Done!`)
});
Observable
Observer
Operators
Sono le funzioni che ci permettono di manipolare gli observables.
Operators = RxJs
// da qualsiasi valore Rx.Observable.of(0, 3, 'fevr', ['a', 'b']);
// da qualsiasi valore Rx.Observable.of(0, 3, 'fevr', ['a', 'b']);
// da un array o da una promise Rx.Observable.from([1, 2, 3]);
// da qualsiasi valore Rx.Observable.of(0, 3, 'fevr', ['a', 'b']);
// da un array o da una promise Rx.Observable.from([1, 2, 3]);
// da un evento Rx.Observable.fromEvent(myBtn, 'click');
// da qualsiasi valore Rx.Observable.of(0, 3, 'fevr', ['a', 'b']);
// da un array o da una promise Rx.Observable.from([1, 2, 3]);
// da un evento Rx.Observable.fromEvent(myBtn, 'click');
// da un intervallo (tipo setTimeout) Rx.Observable.interval(1000);
// da un array o da una promise Rx.Observable.from([1, 2, 3]);
// da un evento Rx.Observable.fromEvent(myBtn, 'click');
// da un intervallo (tipo setTimeout) Rx.Observable.interval(1000);
// da un timer (delay, interval) Rx.Observable.timer(100, 1000);
// da qualsiasi valore Rx.Observable.of(0, 3, 'fevr', ['a', 'b']);
// da un range Rx.Observable.range(30, 10);
// da un range Rx.Observable.range(30, 10);
// da una funzione con bindCallback const fetch = (url, callback) => { //...
callback('data')
}
const rxFetch = Rx.Observable.bindCallback(fetch);
// da un range Rx.Observable.range(30, 10);
// da una funzione con bindCallback const fetch = (url, callback) => { //...
callback('data')
}
const rxFetch = Rx.Observable.bindCallback(fetch);
// never Rx.Observable.never();
const mouseMove$ = Rx.Observable.fromEvent(document, 'mousemove');
const click$ = Rx.Observable.fromEvent(document, 'click');
const uiEvents$ = Rx.Observable.merge(mouseMove$, click$)
.subscribe(e => console.log(e.type));
// click
// mousemove
// mousemove
// mousemove
// click
// mousemove
// mousemove
// mousemove
// mousemove
const interval100$ = Rx.Observable.interval(100)
.take(5);
const interval2000$ = Rx.Observable.interval(2000);
const intervalConcat$ = Rx.Observable.concat(interval100$, interval2000$)
.subscribe(console.log);
// 0
// 1
// 2
// 3
// 4
// 0
// 1
// 2
// 3
// ...
const interval100$ = Rx.Observable.interval(100);
const interval2000$ = Rx.Observable.interval(2000);
const intervalConcat$ = Rx.Observable.combineLatest(interval100$, interval2000$)
.subscribe(console.log);
// [19, 0]
// [20, 0]
// [21, 0]
// ...
// [39, 1]
// ...
// [39, 1]
// ...
// [59, 2]
http://codepen.io/giuliocollesei/pen/vxjyjp/
http://codepen.io/giuliocollesei/pen/ryvjKG
Documentazione ufficiale:
http://reactivex.io/rxjs/
Introduzione FRP by André Staltz
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
Video corsi su egghead.io
https://egghead.io/technologies/rx
RxMarbles (stream interattivi)
http://rxmarbles.com/