Functional programming using underscorejs

Preview:

Citation preview

Functional Programmingusing Underscore.js

othree @ OSDC 2013

me

• PhD Candidate

• Front End Engineer

• On the way learning good from functional programming languages

Function ofFunctional Language

• Pure function

• First class citizen

• Higher order function

• ...

Pure Function

• Side effect free

• Same input, same output

• ex: trigonometric functions

First Class Citizen

• Function like variable

• ex: function expression

var f = function () { /*...*/ };

Higher Order Function

• Function takes or return functions

• ex: event listener

Take a LookExamples from ‘Pure, functional JavaScript’

http://cjohansen.no/talks/2012/sdc-functional/

[ { name: 'Gates', gender: 'M', org: 'M$' }, { name: 'Peter' gender: 'M', org: 'Hㄒㄈ' }]

"Mentioned by Gates, Peter, Jobs"

var str = "Mentioned by ";

for (var i = 0, l = tweeps.length; i < l; ++i) { str += tweeps[i].name; if (i < tweeps.length - 1) { str += ", "; }}

[ { name: 'Gates', gender: 'M', org: 'M$' }, { name: 'Peter' gender: 'M', org: 'Hㄒㄈ' }]

[ 'Gates', 'Peter']

var names = [];

for (var i = 0, l = tweeps.length; i < l; ++i) { names.push(tweeps[i].name);}

var str = "Mentioned by " + names.join(", ");

var names = tweeps.map(function (tweep) { return tweep.name;});

var names = tweeps.map(function (t) { return t.name; });

var str = "Mentioned by " + tweeps.map(function (t) { return t.name;}).join(", ");

function prop(name) { return function (object) { return object[name]; };}

var str = "Mentioned by " + tweeps.map(prop("name")).join(", ");

Case 2

[ { getSummary: function () { return { text: 'Summaries', html: '<p>Summaries</p>' }; } }, { getSummary: function () { return {text: 'Summaried'}; } }, ...]

<div> <p>Summaries</p> <p>Summaried</p> <p>Summary</p></div>

buildSummary: function () { var div = document.createElement("div"), p;

for (var i = 0, l = this.components.length; i < l; ++i) { p = document.createElement("p"); p.innerHTML = this.components[i].getSummary().text; div.appendChild(p); }

return div;}

DOM functions

var ul = cull.dom.el("ul");ul.nodeType === 1 // true

https://github.com/culljs/dome/

var ul = cull.dom.el("ul", { className: "bands" });

//var li = cull.dom.el("li", "Execration");var ul = cull.dom.el("ul", { className: "bands" }, li);

var ul = cull.partial(cull.dom.el, "ul");var li = cull.partial(cull.dom.el, "li");

["a", "br", "code", "div", ...].forEach(function (tagName) { cull.dom.el[tagName] = cull.partial(cull.dom.el, tagName);});

//["a", "br", "code", "div", ...].forEach(function (tagName) { root[tagName] = cull.partial(cull.dom.el, tagName);});

buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));}

buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));} 1

buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));} 1 2

buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));} 1 23

buildSummary: function () { return div(this.components. map(function (component) { return component.getSummary(); }).map(function (summary) { return summary.text; }).map(function (text) { return p(text); }));}

function func(name) { return function (object) { return object[name](); };}

buildSummary: function () { return div(this.components. map(func("getSummary")). map(function (summary) { return summary.text; }).map(function (text) { return p(text); }));}

buildSummary: function () { return div(this.components. map(func("getSummary")). map(prop("text")). map(function (text) { return p(text); }));}

buildSummary: function () { return div(this.components. map(func("getSummary")). map(prop("text")). map(p));}

var summarize = compose([p, prop("text"), func("getSummary")]);

var callGetSummary = func("getSummary");var getText = prop("text");var summarize = compose([p, getText, callGetSummary]);

// summarize(obj);// => callGetSummary(obj)// => getText(callGetSummary(obj))// => p(getText(callGetSummary(obj)))

buildSummary: function () { var summarize = compose([p, prop("text"), func("getSummary")]); return div(this.components.map(summarize));}

var summarize = compose([p, prop("text"), func("getSummary")]);

// ...

buildSummary: function () { return div(this.components.map(summarize));}

Functional Programming in JavaScript

Native

• forEach

• map/reduce

• filter

Functional JavaScript

• by Oliver Steele at 2007

• First functional JavaScript Library I know

Underscore.js

• by Jeremy Ashkenas from DocumentCloud

• “Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support”

Lo-Dash

• Will talk later

cull.js

• by Christian Johansen and Magnar Sveen

• “Cull is a toolbelt for writing functional javascript.”

• Used in the examples above

https://github.com/culljs/culljs

LiveScript & prelude.ls

• by George Zahariev

• A new compile to JavaScript language fork from Coco

• Stay in this room until tomorrow, Mindos have a talk about LiveScript

GHCJS

• by Hamish Mackenzie, Victor Nazarov, Luite Stegeman

• Haskell to JavaScript compiler

Underscore.js

• compose

• map/reduce

• filter

• pluck

var str = "Mentioned by " + tweeps.map(prop("name")).join(", ");

var str = "Mentioned by " + _.reduce( _.map(tweeps, function (t) { return t.name; }), function (memo, name, i) { return (i == 0) ? name : memo + ', ' + name; }, '');

var str = "Mentioned by " + _(tweeps) .chain() .map(function (t) { return t.name; }) .reduce(function (memo, name, i) { return (i == 0) ? name : memo + ', ' + name; }, '') .value();

var str = "Mentioned by " + _(tweeps) .map(function (t) { return t.name; }) .join(', ');

var str = "Mentioned by " + _(tweeps).pluck('name').join(', ');

Still Not Enough

• curry, partial

• prop, func from above example

Lo-Dash

Functional Programmingusing Underscore.js

othree @ OSDC 2013.1

Functional Programmingusing Underscore.jsLo-Dash

othree @ OSDC 2013.1

-

_

_-

_-

What is Lo-Dash

• Underscore.js fork by John-David Dalton, Kit Cambridge, and Mathias Bynens

Difference

• Better performance

• Robust result

• Larger file size

• AMD supports

• Auto chain

• More power: cloneDeep, partial, result...

_.partial

var greet = function(greeting, name) { return greeting + ' ' + name; };var hi = _.partial(greet, 'hi');hi('moe');// ! 'hi moe'

http://lodash.com/docs#partial

_.result

var object = { 'cheese': 'crumpets', 'stuff': function () { return 'nonsense'; }};

_.result(object, 'cheese');// ! 'crumpets'

_.result(object, 'stuff');// ! 'nonsense'

http://lodash.com/docs#result

With Lo-Dash

var summarize = compose([p, prop("text"), func("getSummary")]);

// ...

buildSummary: function () { return div(map(summarize), this.components);}

var summarize = _.compose( p, _.partialRight(_.result, 'name'), _.partialRight(_.result, 'getSummary') );

// ...

buildSummary: function () { return div(_.map(this.components, summarize));}

Performance?

Bad..

• Take benefits from functional programming

• Not change everything to functional

• Library helps, ex: lo-dash

ReferencesFurther Readings

http://shop.oreilly.com/product/0636920028857.do

Not

Yet

Rel

ease

d

Questions?

http://www.flickr.com/photos/roman/5610736/

Recommended