Final Thoughts

In notebook:
FrontEndMasters Hardcore Functional
Created at:
2017-07-10
Updated:
2017-07-16
Tags:
Functional Programming JavaScript jQuery libraries

Explain the last state (in the repo) of app.js

  /* global define */
define([
  'jquery'
, 'ramda'
, 'pointfree'
, 'Maybe'
, 'player'
, 'io'
, 'bacon'
, 'http'
], function($, _, P, Maybe, Player, io, bacon, http) {
  'use strict';
  io.extendFn();

  // HELPERS ///////////////////////////////////////////
  var compose = P.compose;
  var map = P.map;
  var log = function(x) { console.log(x); return x; }
  var fork = _.curry(function(f, future) { return future.fork(log, f); })
  var setHtml = _.curry(function(sel, x) { return $(sel).html(x); });
  var listen = _.curry(function (event, target) {
    return bacon.fromEventTarget(target, event);
  });
  var getData = _.curry(function(name, elt) { return $(elt).data(name); });
  var last = function(ar) { return ar[ar.length - 1]; };

  // PURE //////////////////////////////////////////////////
  
  //  api_key :: String
  var api_key = 'AIzaSyAWoa7aqds2Cx_drrrb5FPsRObFa7Dxkfg';

  //+ eventValue :: DomEvent -> String
  var eventValue = compose(_.get('value'), _.get('target'));

  //+ valueStream :: DomEvent -> EventStream String
  var valueStream = compose(map(eventValue), listen('keyup'));

  //+ termToUrl :: String -> URL
  var termToUrl = function(term) {
    return 'https://www.googleapis.com/youtube/v3/search?' +
      $.param({part: 'snippet', q: term, key: api_key});
  };

  //+ urlStream :: DomEvent -> EventStream String
  var urlStream = compose(map(termToUrl), valueStream);

  //+ getInputStream :: Selector -> IO EventStream String
  var getInputStream = compose(map(urlStream), $.toIO());

  //+ render :: Entry -> Dom
  var render = function(e) {
    return $('<li/>', {text: e.snippet.title, 'data-youtubeid': e.id.videoId});
  };

  //+ videoEntries :: YoutubeResponse -> [Dom]
  var videoEntries = compose(map(render), _.get('items'));

  //+ search :: URL -> Future [Dom]
  var search = compose(map(videoEntries), http.getJSON);

  //+ DomElement -> EventStream DomElement
  var clickStream = compose(map(_.get('target')), listen('click'));

  //+ URL -> String
  var idInUrl = compose(last, _.split('/'));

  //+ youtubeLink :: DomElement -> Maybe ID
  var youtubeId = compose(map(idInUrl), Maybe, getData('youtubeid'));

  // IMPURE /////////////////////////////////////////////////////

  getInputStream('#search').runIO().onValue(
    compose(fork(setHtml('#results')), search)
  );

  // **** EXPLAIN this part
  // this should get the click target and see if it's a search result element (youtubeId) (?)
  // this is why whe have a Maybe in the youtubeId definiton
  // if where the user clicked does not have a youtubeId then the Maybe will just stop
  // this is how they did EVENT DELEGATION and bubbling handling
  clickStream(document).onValue(
    compose(map(compose(setHtml('#player'), Player.create)), youtubeId)
  );

});

Whole app is testable, pure, composable

Brian says that applicatives and monoids are much easier than monads, but didn't have the time to cover them but are in fact on the slides (slide 142).