Functional Reactive Programming

Functional Reactive Programming

NodePDX 2013

3e09fee7b359be847ed5fa48f524a3d3?s=128

Christopher Meiklejohn

May 17, 2013
Tweet

Transcript

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

  2. Thursday, May 16, 13

  3. MOTIVATIONS Thursday, May 16, 13

  4. VOID CALLBACKS FORCE MUTATION Thursday, May 16, 13

  5. 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
  6. MULTIPLE ASSIGNMENT FOR VARIABLES Thursday, May 16, 13

  7. 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
  8. 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
  9. REACTIVE PROGRAMMING Thursday, May 16, 13

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

  11. A = B + C C = D + E

    Thursday, May 16, 13
  12. DATAFLOW LANGUAGES LUSTRE LUCID VERILOG Thursday, May 16, 13

  13. LUSTRE Thursday, May 16, 13

  14. FUNCTIONAL REACTIVE PROGRAMMING Thursday, May 16, 13

  15. EVENT STREAMS Thursday, May 16, 13

  16. KP Thursday, May 16, 13

  17. KP EKP filter() Thursday, May 16, 13

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

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

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

  21. SIGNALS (BEHAVIORS) Thursday, May 16, 13

  22. I Thursday, May 16, 13

  23. I I2 lift() Thursday, May 16, 13

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

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

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

  27. SWITCHING Thursday, May 16, 13

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

  29. KP AKP switch() Thursday, May 16, 13

  30. KP BKP switch() Thursday, May 16, 13

  31. GLITCH FREE PROPAGATION Thursday, May 16, 13

  32. A = B + C A B C Thursday, May

    16, 13
  33. A = B + C C = D + E

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

    E A B C D E Thursday, May 16, 13
  35. 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
  36. COMMON OPERATIONS Thursday, May 16, 13

  37. SEND HOLD MERGE CONSTANT CHANGES BIND SWITCH MAP NOT DELAY

    COLLECT FILTER SEND ONCE LIFT SKIP-FIRST FILTER-REPEATS SNAPSHOT Thursday, May 16, 13
  38. IMPLEMENTATIONS Thursday, May 16, 13

  39. FLAPJAX Thursday, May 16, 13

  40. • Language and Framework • Compiler in Haskell • Brown

    University 2009 (OOPSLA 2009) • First major implementation in JavaScript FLAPJAX Thursday, May 16, 13
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. RXJS Thursday, May 16, 13

  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. BACON.JS Thursday, May 16, 13

  56. BACON.JS • Inspired by Reactive Banana and RxJS • Flowdock,

    open sourced in 2013 Thursday, May 16, 13
  57. 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
  58. 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
  59. 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
  60. 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
  61. 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
  62. SO, NODE? Thursday, May 16, 13

  63. NPM INSTALL RX Thursday, May 16, 13

  64. 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
  65. 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
  66. FLAPJAX, ETC. Thursday, May 16, 13

  67. OTHER OPTIONS Thursday, May 16, 13

  68. CLOJURESCRIPT SHAFTY JAVELIN Thursday, May 16, 13

  69. ELM Thursday, May 16, 13

  70. THANKS! Thursday, May 16, 13