Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why Bacon is actually good for your health

Why Bacon is actually good for your health

JSConf.uy 2014 talk by Leonardo Garcia Crespo and Sergio Gianazza.

Sergio Rafael Gianazza

March 15, 2014
Tweet

More Decks by Sergio Rafael Gianazza

Other Decks in Programming

Transcript

  1. Functional Reactive Programming “Functional Reactive Programming (FRP) integrates time flow

    and compositional events into functional programming. This provides an elegant way to express computation in domains such as interactive animations, robotics, computer vision, user interfaces and simulation.” - Extract from Haskell Wiki
  2. map

  3. map numbers numbers.map(f) f(x) = x * 2 t 2

    4 6 8 1 2 3 4 f(1) f(2) f(3) f(4)
  4. merge L1 L1.merge(L2) t ‘C’ ‘F’ ‘J’ ‘C’ ‘F’ L2

    ‘O’ ’N' ‘O’ ‘S’ ‘J’ ‘S’ ’N'
  5. merge L1 L1.merge(L2) t ‘C’ ‘F’ ‘J’ ‘C’ ‘F’ L2

    ‘O’ ’N' ‘O’ ‘S’ ‘J’ ‘.’ ‘S’ ’N' ‘.’
  6. merge L1 L1.merge(L2) t ‘C’ ‘F’ ‘J’ ‘C’ ‘F’ L2

    ‘O’ ’N' ‘O’ ‘S’ ‘J’ ‘.’ ‘U’ ‘S’ ’N' ‘.’ ‘U’
  7. merge L1 L1.merge(L2) t ‘C’ ‘F’ ‘J’ ‘C’ ‘F’ L2

    ‘O’ ’N' ‘O’ ‘S’ ‘J’ ‘.’ ‘U’ ‘Y’ ‘Y’ ‘S’ ’N' ‘.’ ‘U’
  8. scan chars chars.scan(‘’,f) f(x,y) = concat(x,y) t ‘’ ‘h’ ‘h’

    ‘e’ seed f(‘’, ‘h’) f(‘h’, ‘e’)
  9. scan chars chars.scan(‘’,f) f(x,y) = concat(x,y) t ‘’ ‘h’ ‘he’

    ‘h’ ‘e’ seed f(‘’, ‘h’) f(‘h’, ‘e’)
  10. scan chars chars.scan(‘’,f) f(x,y) = concat(x,y) t ‘’ ‘h’ ‘he’

    ‘hel’ ‘h’ ‘e’ ‘l’ seed f(‘’, ‘h’) f(‘h’, ‘e’) f(‘he’, ‘l’)
  11. scan chars chars.scan(‘’,f) f(x,y) = concat(x,y) t ‘’ ‘h’ ‘he’

    ‘hel’ ‘h’ ‘e’ ‘l’ seed f(‘’, ‘h’) f(‘h’, ‘e’) f(‘he’, ‘l’) ‘hell’ ‘l’ f(‘hel’, ‘l’)
  12. scan chars chars.scan(‘’,f) f(x,y) = concat(x,y) t ‘’ ‘h’ ‘he’

    ‘hel’ ‘h’ ‘e’ ‘l’ seed f(‘’, ‘h’) f(‘h’, ‘e’) f(‘he’, ‘l’) ‘hell’ ‘l’ f(‘hel’, ‘l’) ‘hello’ ‘o’ f(‘hell’, ‘o’)
  13. Bacon.js 1 // From jQuery! 2 $('#myButtom').asEventStream('click');! 3 ! 4

    // From callback! 5 Bacon.fromCallback(function(callback) {! 6 setTimeout(function() {! 7 callback("Bacon!");! 8 }, 1000)! 9 });! 10 ! 11 //From node callback! 12 var Bacon = require('baconjs').Bacon,! 13 fs = require('fs');! 14 var read = Bacon.fromNodeCallback(fs.readFile, 'input.txt');! 15 ! 16 // And many more!!! Event Stream example:
  14. Bacon.js 1 var up = $('#up').asEventStream('click');! 2 var down =

    $('#down').asEventStream('click');! 3 ! 4 var upOcurrences = up.map(1);! 5 var downOcurrences = up.down(-1); map example:
  15. Bacon.js 1 var up = $('#up').asEventStream('click');! 2 var down =

    $('#down').asEventStream('click');! 3 ! 4 var upOcurrences = up.map(1);! 5 var downOcurrences = up.down(-1);! 6 ! 7 var ocurrences = upOcurrences.merge(downOcurrences); merge example:
  16. Bacon.js 1 var up = $('#up').asEventStream('click');! 2 var down =

    $('#down').asEventStream('click');! 3 ! 4 var upOcurrences = up.map(1);! 5 var downOcurrences = up.down(-1);! 6 ! 7 var ocurrences = upOcurrences.merge(downOcurrences);! 8 ! 9 var count = ocurrences.scan(0, function(accum, value) { return accum + value; });! 10 ! 11 count.assign($('#myCount'), 'text'); scan example:
  17. Bacon.js 1 var up = $('#up').asEventStream('click');! 2 var down =

    $('#down').asEventStream('click');! 3 ! 4 var upOcurrences = up.map(1);! 5 var downOcurrences = up.down(-1);! 6 ! 7 var ocurrences = upOcurrences.merge(downOcurrences);! 8 ! 9 var count = ocurrences.scan(0, function(accum, value) { return accum + value; });! 10 ! 11 count.assign($('#myCount'), 'text');! 12 ! 13 var tens = count.filter(function(value) { return value % 10 == 0; })! 14 .map(function(value) { return value / 10; });! 15 ! 16 tens.assign($('#myTensCount'), 'text')); filter example:
  18. Bacon.js 1 // With Scan! 2 var clicks = $('#myButton').asEventStream('click');!

    3 var clickCount = clicks.scan(0, function(x, y) { return x + 1 });! 4 ! 5 // With toProperty! 6 var textValue = #('#input').asEventStream('keypress')! 7 .map('.target')! 8 .map('.value')! 9 .toProperty("default value"); property example:
  19. Examples •No imperative event handling! •Define alarms to trigger in

    the future. •Hours, minutes and seconds are separate events. Timer:
  20. Examples Timer - Setup: 1 // Set up timer seconds,

    minutes, and hours! 2 var seconds = Bacon.interval(1000, 'tick')! 3 .scan(0, function(seconds) {! 4 return seconds == 59 ? 0 : (seconds + 1);! 5 })! 6 .map(toTwoDigitsString);! 7 ! 8 var minutes = seconds! 9 .changes()! 10 .filter(isOClock)! 11 .scan(0, function(minutes) {! 12 return minutes == 59 ? 0 : (minutes + 1);! 13 })! 14 .map(toTwoDigitsString);! 15 ! 16 var hours = minutes! 17 .changes()! 18 .filter(isOClock)! 19 .scan(0, function(hours) {! 20 return hours == 23 ? 0 : (hours + 1);! 21 })! 22 .map(toTwoDigitsString);
  21. Examples Timer - Combine: 1 // Build full hour from

    the 3 properties! 2 var fullHour = hours.map(Array)! 3 .combine(minutes.map(Array), '.concat')! 4 .combine(seconds.map(Array), '.concat')! 5 .map(function(arr) {! 6 return arr.join(':');! 7 });! 8
  22. Examples 1 // Set up alarms! 2 var alarmTime =

    $('#alarmTime').asEventStream('keypress');! 3 var alarmSet = $('#setAlarm').asEventStream('click');! 4 ! 5 var currentAlarm = alarmTime.sampledBy(alarmSet)! 6 .map('.target').map('.value');! 7 ! 8 var alarmSignal = currentAlarm.flatMap(function(time) {! 9 return fullHour.filter(function(current) { return current == time; });! 10 });! 11 Timer - Setup alarm:
  23. Examples 1 // Bind everything to the DOM! 2 seconds.assign($("#seconds"),

    'text');! 3 minutes.assign($("#minutes"), 'text');! 4 hours.assign($("#hour"), 'text');! 5 ! 6 currentAlarm.assign(function(alarm) {! 7 $('#currentAlarm').append('<li>'+alarm+'</li>');! 8 });! 9 Timer - DOM Binding:
  24. Examples 1 // Fire the alarm!!! 2 alarmSignal.onValue(function(time) {! 3

    alert('Alarm sounds! It\'s ' + time);! 4 }); Timer - Fire the alarm:
  25. Examples Backbone - Event streams: 1 // Get an event

    stream for all add remove and reset events in the collection! 2 var reposProp = eventStream(repos, 'add remove reset').map(function(args) {! 3 return args[1];! 4 ! 5 // and make it a property!! 6 }).toProperty(repos);! 7 ! 8 // Results count is easy!! 9 var resultsCount = reposProp.map('.models').map('.length');
  26. Examples Backbone - DOM Bindings: 1 // Render the repos!

    2 reposProp.map(renderRepos).assign($('#list'), 'html');! 3 // Render the counts! 4 resultsCount.assign($('#resultsCount'), 'text');
  27. Examples Backbone - Model search: 1 // Just for fun,

    we assign the input to a backbone property! 2 var filterSearches = $('#filter').asEventStream('input')! 3 .debounce(300)! 4 .map('.target').map('.value')! 5 .assign(filter, 'set', 'filter');! 6 ! 7 // Create a model for the filter input! 8 var filter = new Backbone.Model({ filter: '' });! 9 ! 10 // We make it a Bacon Property!! 11 modelProperty(filter, 'filter')! 12 .skipDuplicates()! 13 .filter(function(text) {! 14 return text.length >= 3 || text === '';! 15 })! 16 .onValue(function(text) { repos.search(text); });
  28. Examples Angular - Event stream: 1 var passwordInput = $scope!

    2 .$watchAsProperty('password');! 3 ! 4 var passwordsEqual = passwordInput! 5 .combine(! 6 $scope.$watchAsProperty('passwordConfirm'),! 7 function(pass, confirm) {! 8 return {! 9 password: pass,! 10 confirm: confirm! 11 };! 12 }! 13 )! 14 .map(function(it) {! 15 return it.password === it.confirm;! 16 })! 17 .toProperty();! 18 ! 19 var usernameInput = $scope! 20 .$watchAsProperty('username');
  29. Examples Angular - Basic checks: 1 var passwordIsValid = passwordInput!

    2 .map(longerThanOrEqual(5));! 3 ! 4 var usernameIsFree = usernameInput! 5 .changes()! 6 .filter(longerThan(2))! 7 .flatMapLatest(function(it) { return Bacon.later(2000, it === "user"); })! 8 .merge(usernameInput.map(false).changes())! 9 .toProperty(false);
  30. Examples Angular - Check username: 1 usernameIsFree! 2 .and(passwordIsValid)! 3

    .and(passwordsEqual)! 4 .digest($scope, 'formValid');! 5 ! 6 usernameIsFree! 7 .changes()! 8 .filter(identity)! 9 .map(Bacon.constant("free"))! 10 .merge(usernameIsFree.changes().not().filter(identity).map(Bacon.constant("taken")))! 11 .merge(usernameInput.map(Bacon.constant("loading")).changes())! 12 .merge(! 13 usernameInput! 14 .filter(shorterThan(2))! 15 .map(Bacon.constant("empty"))! 16 .changes()! 17 )! 18 .digest($scope, 'usernameState');
  31. Examples Angular - Check password: 1 passwordIsValid! 2 .changes()! 3

    .not()! 4 .digest($scope, 'passwordInvalid');! 5 ! 6 passwordsEqual! 7 .changes()! 8 .not()! 9 .digest($scope, 'passwordsDontMatch');