$30 off During Our Annual Pro Sale. View Details »

Functional Reactive Programming

Functional Reactive Programming

NodePDX 2013

Christopher Meiklejohn

May 17, 2013
Tweet

More Decks by Christopher Meiklejohn

Other Decks in Programming

Transcript

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

    View Slide

  2. Thursday, May 16, 13

    View Slide

  3. MOTIVATIONS
    Thursday, May 16, 13

    View Slide

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

    View Slide

  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

    View Slide

  6. MULTIPLE ASSIGNMENT
    FOR VARIABLES
    Thursday, May 16, 13

    View Slide

  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

    View Slide

  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

    View Slide

  9. REACTIVE PROGRAMMING
    Thursday, May 16, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. LUSTRE
    Thursday, May 16, 13

    View Slide

  14. FUNCTIONAL
    REACTIVE PROGRAMMING
    Thursday, May 16, 13

    View Slide

  15. EVENT STREAMS
    Thursday, May 16, 13

    View Slide

  16. KP
    Thursday, May 16, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. I
    Thursday, May 16, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  27. SWITCHING
    Thursday, May 16, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. GLITCH FREE PROPAGATION
    Thursday, May 16, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  36. COMMON OPERATIONS
    Thursday, May 16, 13

    View Slide

  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

    View Slide

  38. IMPLEMENTATIONS
    Thursday, May 16, 13

    View Slide

  39. FLAPJAX
    Thursday, May 16, 13

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  47. RXJS
    Thursday, May 16, 13

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  55. BACON.JS
    Thursday, May 16, 13

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  62. SO, NODE?
    Thursday, May 16, 13

    View Slide

  63. NPM INSTALL RX
    Thursday, May 16, 13

    View Slide

  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

    View Slide

  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

    View Slide

  66. FLAPJAX, ETC.
    Thursday, May 16, 13

    View Slide

  67. OTHER OPTIONS
    Thursday, May 16, 13

    View Slide

  68. CLOJURESCRIPT
    SHAFTY JAVELIN
    Thursday, May 16, 13

    View Slide

  69. ELM
    Thursday, May 16, 13

    View Slide

  70. THANKS!
    Thursday, May 16, 13

    View Slide