Slide 1

Slide 1 text

(FUNCTIONAL) REACTIVE PROGRAMMING Christopher Meiklejohn @cmeik Thursday, May 16, 13

Slide 2

Slide 2 text

Thursday, May 16, 13

Slide 3

Slide 3 text

MOTIVATIONS Thursday, May 16, 13

Slide 4

Slide 4 text

VOID CALLBACKS FORCE MUTATION Thursday, May 16, 13

Slide 5

Slide 5 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function handleClick(ev) { return computed = compute(ev.context); } Thursday, May 16, 13

Slide 6

Slide 6 text

MULTIPLE ASSIGNMENT FOR VARIABLES Thursday, May 16, 13

Slide 7

Slide 7 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function handleClick(ev) { // jQuery call to change background color } function handleMouseOver(ev) { // jQuery call to change background color } Thursday, May 16, 13

Slide 8

Slide 8 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function handleClick(ev) { changeBackgroundColor(...); } function handleMouseOver(ev) { changeBackgroundColor(...); } function changeBackgroundColor(color) { // jQuery call to change background color } Thursday, May 16, 13

Slide 9

Slide 9 text

REACTIVE PROGRAMMING Thursday, May 16, 13

Slide 10

Slide 10 text

A = B + C Thursday, May 16, 13

Slide 11

Slide 11 text

A = B + C C = D + E Thursday, May 16, 13

Slide 12

Slide 12 text

DATAFLOW LANGUAGES LUSTRE LUCID VERILOG Thursday, May 16, 13

Slide 13

Slide 13 text

LUSTRE Thursday, May 16, 13

Slide 14

Slide 14 text

FUNCTIONAL REACTIVE PROGRAMMING Thursday, May 16, 13

Slide 15

Slide 15 text

EVENT STREAMS Thursday, May 16, 13

Slide 16

Slide 16 text

KP Thursday, May 16, 13

Slide 17

Slide 17 text

KP EKP filter() Thursday, May 16, 13

Slide 18

Slide 18 text

KP EKP filter() SKP filter() Thursday, May 16, 13

Slide 19

Slide 19 text

KP EKP filter() 1 map() Thursday, May 16, 13

Slide 20

Slide 20 text

MK ME merge() KP Thursday, May 16, 13

Slide 21

Slide 21 text

SIGNALS (BEHAVIORS) Thursday, May 16, 13

Slide 22

Slide 22 text

I Thursday, May 16, 13

Slide 23

Slide 23 text

I I2 lift() Thursday, May 16, 13

Slide 24

Slide 24 text

I I2 lift() C changes() Thursday, May 16, 13

Slide 25

Slide 25 text

I I2 lift() C changes() 1 map() Thursday, May 16, 13

Slide 26

Slide 26 text

I3 I2 lift2() I1 Thursday, May 16, 13

Slide 27

Slide 27 text

SWITCHING Thursday, May 16, 13

Slide 28

Slide 28 text

KP BKP AKP switch() Thursday, May 16, 13

Slide 29

Slide 29 text

KP AKP switch() Thursday, May 16, 13

Slide 30

Slide 30 text

KP BKP switch() Thursday, May 16, 13

Slide 31

Slide 31 text

GLITCH FREE PROPAGATION Thursday, May 16, 13

Slide 32

Slide 32 text

A = B + C A B C Thursday, May 16, 13

Slide 33

Slide 33 text

A = B + C C = D + E A B C D E Thursday, May 16, 13

Slide 34

Slide 34 text

A = B + C C = LIFT2 + D, E A B C D E Thursday, May 16, 13

Slide 35

Slide 35 text

var a = y + 0; var b = y + a; var c = b + 1; var d = c % 2; var e = 5 / d; A B C Y D E Thursday, May 16, 13

Slide 36

Slide 36 text

COMMON OPERATIONS Thursday, May 16, 13

Slide 37

Slide 37 text

SEND HOLD MERGE CONSTANT CHANGES BIND SWITCH MAP NOT DELAY COLLECT FILTER SEND ONCE LIFT SKIP-FIRST FILTER-REPEATS SNAPSHOT Thursday, May 16, 13

Slide 38

Slide 38 text

IMPLEMENTATIONS Thursday, May 16, 13

Slide 39

Slide 39 text

FLAPJAX Thursday, May 16, 13

Slide 40

Slide 40 text

• Language and Framework • Compiler in Haskell • Brown University 2009 (OOPSLA 2009) • First major implementation in JavaScript FLAPJAX Thursday, May 16, 13

Slide 41

Slide 41 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var tenthB = timerB(100); Thursday, May 16, 13

Slide 42

Slide 42 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var tenthB = timerB(100); var secondB = Math.floor(tenthB / 1000); Thursday, May 16, 13

Slide 43

Slide 43 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var tenthB = timerB(100); var secondB = Math.floor(tenthB / 1000); var hashE = timerE(50).mapE(function() { return window.location.hash; }); Thursday, May 16, 13

Slide 44

Slide 44 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var tenthB = timerB(100); var secondB = Math.floor(tenthB / 1000); var hashE = timerE(50).mapE(function() { return window.location.hash; }); var routeE = hashE.mapE(function(h) { return h ? h.slice(1) : defaultRoute }); Thursday, May 16, 13

Slide 45

Slide 45 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var tenthB = timerB(100); var secondB = Math.floor(tenthB / 1000); var hashE = timerE(50).mapE(function() { return window.location.hash; }); var routeE = hashE.mapE(function(h) { return h ? h.slice(1) : defaultRoute }); var routeB = startsWith(filterRepeatsE(routeE), defaultRoute); Thursday, May 16, 13

Slide 46

Slide 46 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var startEditEe = extractEventE(label, 'dblclick'). mapE(function() { li.className = 'editing'; edit.focus(); return extractValueE(edit); }); var stopEditEe = mergeE(returnPressE(edit), blurE(edit)). mapE(function() { li.className = todo.completed ? 'completed' : ''; return oneE(sentinel); }); var eventsE = switchE(mergeE(startEditEe, stopEditEe)); Thursday, May 16, 13

Slide 47

Slide 47 text

RXJS Thursday, May 16, 13

Slide 48

Slide 48 text

RXJS (Reactive Extensions) • Authored by the Cloud Programmability Group at Microsoft • Set of libraries • Bindings in various languages providing “reactivity” • Observables and observers • Provides scheduling and LINQ for querying Thursday, May 16, 13

Slide 49

Slide 49 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /* Only get the value from each key up */ var keyups = Rx.Observable.fromEvent(input, 'keyup') .select(function (e) { return e.target.value; }) .where(function (text) { return text.length > 2; }); Thursday, May 16, 13

Slide 50

Slide 50 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /* Only get the value from each key up */ var keyups = Rx.Observable.fromEvent(input, 'keyup') .select(function (e) { return e.target.value; }) .where(function (text) { return text.length > 2; }); /* Now throttle/debounce the input for 500ms */ var throttled = keyups .throttle(500 /* ms */); Thursday, May 16, 13

Slide 51

Slide 51 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /* Only get the value from each key up */ var keyups = Rx.Observable.fromEvent(input, 'keyup') .select(function (e) { return e.target.value; }) .where(function (text) { return text.length > 2; }); /* Now throttle/debounce the input for 500ms */ var throttled = keyups .throttle(500 /* ms */); /* Now get only distinct values, so we eliminate the arrows */ var distinct = keyups .distinctUntilChanged(); Thursday, May 16, 13

Slide 52

Slide 52 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function searchWikipedia(term) { var url = 'http://en.wikipedia.org/w/api.php?action=opensearch' + '&format=json' + '&search=' + encodeURI(term); return Rx.Observable.getJSONPRequest(url); } Thursday, May 16, 13

Slide 53

Slide 53 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function searchWikipedia(term) { var url = 'http://en.wikipedia.org/w/api.php?action=opensearch' + '&format=json' + '&search=' + encodeURI(term); return Rx.Observable.getJSONPRequest(url); } var suggestions = distinct .select(function (text) { return searchWikipedia(text); }) .switchLatest() .where(function (data) { return data.length == 2 && data[1].length > 0; }); Thursday, May 16, 13

Slide 54

Slide 54 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var suggestions = distinct .select(function (text) { return searchWikipedia(text); }) .switchLatest() .where(function (data) { return data.length == 2 && data[1].length > 0; }); suggestions.subscribe( function (data) { var results = data[1]; /* Do something with the data like binding */ }, function (e) { /* handle any errors */ }); Thursday, May 16, 13

Slide 55

Slide 55 text

BACON.JS Thursday, May 16, 13

Slide 56

Slide 56 text

BACON.JS • Inspired by Reactive Banana and RxJS • Flowdock, open sourced in 2013 Thursday, May 16, 13

Slide 57

Slide 57 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var clicks = $("h1").asEventStream("click"); clicks.onValue(function() { alert("you clicked the h1 element") }); Thursday, May 16, 13

Slide 58

Slide 58 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var clicks = $("h1").asEventStream("click"); clicks.onValue(function() { alert("you clicked the h1 element") }); var plus = $("#plus").asEventStream("click").map(1); var minus = $("#minus").asEventStream("click").map(-1); var both = plus.merge(minus); Thursday, May 16, 13

Slide 59

Slide 59 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var clicks = $("h1").asEventStream("click"); clicks.onValue(function() { alert("you clicked the h1 element") }); var plus = $("#plus").asEventStream("click").map(1); var minus = $("#minus").asEventStream("click").map(-1); var both = plus.merge(minus); function add(x, y) { return x + y }; var counter = both.scan(0, add); counter.onValue(function(sum) { $("#sum").text(sum) }); Thursday, May 16, 13

Slide 60

Slide 60 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var clicks = $("h1").asEventStream("click"); clicks.onValue(function() { alert("you clicked the h1 element") }); var plus = $("#plus").asEventStream("click").map(1); var minus = $("#minus").asEventStream("click").map(-1); var both = plus.merge(minus); function add(x, y) { return x + y }; var counter = both.scan(0, add); counter.onValue(function(sum) { $("#sum").text(sum) }); function f(a, b) { console.log(a + b) } Bacon.onValues(Bacon.constant(1), Bacon.constant(2), f) Thursday, May 16, 13

Slide 61

Slide 61 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var activity = $(window).asEventStream('mousemove keydown') var active = activity.flatMapLatest(function(event) { return Bacon.once(true).merge(Bacon.later(30000, false)); }).toProperty(true); Thursday, May 16, 13

Slide 62

Slide 62 text

SO, NODE? Thursday, May 16, 13

Slide 63

Slide 63 text

NPM INSTALL RX Thursday, May 16, 13

Slide 64

Slide 64 text

RXJS-NODE • Reified interfaces • Creates asynchronous objects for receiving events • node, child_process, dns, events, fs, http, https, net, path, process, sys Thursday, May 16, 13

Slide 65

Slide 65 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 exports.get = function (options) { var subject = new Rx.AsyncSubject(), handler = handler = function (response) { subject.onNext(response); subject.onCompleted(); }, errHandler = function (err) { subject.onError(err); }; http.get(options, handler).on('error', errHandler); return subject; }; Thursday, May 16, 13

Slide 66

Slide 66 text

FLAPJAX, ETC. Thursday, May 16, 13

Slide 67

Slide 67 text

OTHER OPTIONS Thursday, May 16, 13

Slide 68

Slide 68 text

CLOJURESCRIPT SHAFTY JAVELIN Thursday, May 16, 13

Slide 69

Slide 69 text

ELM Thursday, May 16, 13

Slide 70

Slide 70 text

THANKS! Thursday, May 16, 13