closures and functionals - mit - massachusetts institute...

22
Closures and Functionals 6.170 Recitation Biliana Kaneva

Upload: trancong

Post on 16-Apr-2018

215 views

Category:

Documents


2 download

TRANSCRIPT

Closures and Functionals

6.170 RecitationBiliana Kaneva

Functionals• Javascript functions are first class objects

o Can be passed as arguments to a functiono Can be returned from a functiono Can be assigned to a variableo Can be stored in an object or array

• Functionalso Functions that take functions as an argumento Can be used to capture common idioms

• Exampleso Generators/iteratorso List functionals: map, reduce, filter, etc.

Javascript Arrays• Javascript operations

o pusho unshifto popo shifto spliceo concat

• Autofillingo If set at index beyond length, the elements in

between are set to undefined o If the value not specified in declaration, it is also set

to undefined

> a = [3,5,7][3, 5, 7]> a.push(9)4> a[3, 5, 7, 9]> a.unshift(1)5> a[1, 3, 5, 7, 9]> a.pop()9> a[1, 3, 5, 7]> a.shift()1> a[3, 5, 7]> a.splice(1,1,6)[5]> a[3, 6, 7]> a[4] = 88> a[3, 6, 7, undefined, 8]> a = [3, ,7] > a [3, undefined, 7] 

Generators/Iterators• Common idiom – iterating over a set of elements

• Generators in Pythono Useful feature

• What about Javascript?

>>> def elements(a):...     for i in range(0, len(a)): ...         yield a[i]>>> for e in elements ([1,2,3]):...   print e12

a = [1, 2, 3];for (var i = 0; i < a.length; i++) { 

// do something with a[i]} 

Generators/Iteratorsvar forEach = function(a) { 

return function(body) {for (var i = 0; i < a.length; i++) {

body(a[i]);}

}}

> var a = [1, 2, 3]> var printSquare = function(x) { console.log(x*x); }> var iteratea = forEach(a);> iteratea(printSquare);149> a = [4, 5, 6]; > iteratea(printSquare);149> forEach(a)(printSquare);162536

body is a function

> iterateafunction(body) {

for (var i = 0; i < a.length; i++) {body(a[i]);

}}

Array methods• Can make functionals methods

o Add as properties to Array.prototype

var forEach = function(a) { return function(body) {

for (var i = 0; i < a.length; i++) {body(a[i]);

}}

}

Array.prototype.forEach = function(body) {for (var i = 0; i < this.length; i++) {

body(this[i]);}

}

var sum = function (a) {var result = 0;a.forEach(function (e) {

result += e;});return result;

}

> sum([1,2,3])6

> var a = [1, 2, 3]> var printSquare = function(x) {     

console.log(x*x); }> a.forEach(printSquares)149

Bef

ore

Afte

r

Map

• type› map: list[A] x (A→B) → list[B]

Array.prototype.map = function (f) {var result = [];this.forEach (function (e) {

result.push(f(e));});return result;

}

> var square = function (x) { return x * x; }> var a = [1, 2, 3]; > a.map(square)[1, 4, 9]

Reduce

• Also known as fold• type› reduce: list[A] x (A x B→B) x B → B • Sum with reduce?

Array.prototype.reduce = function (f, base) {var result = base;this.forEach (function (e) {

result = f(e, result);});return result;

}

> var times = function (x, y) { return x * y; }> var a = [1, 2, 3]; > a.reduce(times, 1)6> var add = function (x, y) { return x + y; }> a.reduce(add, 0)6

Filter

• type› filter: list[A] x (A→Bool) → list[A]

• Can combine different operations

Array.prototype.filter = function (p) {var result = [];this.forEach (function (e) {

if (p(e)) result.push(e);});return result;

}

> var a = [1, 2, 3, 4, 5]; > a.filter (function (e) {return e > 2; }) [3, 4, 5]> a.filter (function (e) {return e > 2; }).map(square) [9, 16, 25]

Contains?

• Does this work?• Early returns are a problem

Array.prototype.contains = function (e) {this.forEach(function (x) {

if (x === e) return true;});return false;

}

> var a = [1, 2, 3]; > a.contains(1)false

Contains?

• Reduce to the rescue…• Still have to process allelements

Array.prototype.contains = function (e) {var f = function (x, found) {

return found || (x === e);}return this.reduce(f, false);

}

> var a = [1, 2, 3]; > a.contains(1)true

Closure Example• Fibonacci

var fib = function (i) {if (i < 2) return 1;return fib(i‐1) + fib(i‐2);

}

> console.time('fib'); > fib(20); > console.timeEnd('fib');fib: 7ms> console.time('fib'); > fib(34); > console.timeEnd('fib');fib: 5737ms> console.time('fib'); > fib(35); > console.timeEnd('fib');fib: 9335ms

Memoizationvar memoize = function (f) {

var memo = [];return function (i) {

if (memo[i] === undefined) memo[i] = f(i);

return memo[i];}

}

var mfib = memoize(function (i) {console.log(i);if (i < 2) return 1;return mfib(i‐1) + mfib(i‐2);

});

> mfib(5)5432108> mfib(10)10987689

Memoizationvar memoize = function (f) {

var memo = [];return function (i) {

if (memo[i] === undefined) memo[i] = f(i);

return memo[i];}

}

var mfib = memoize(function (i) {if (i < 2) return 1;return mfib(i‐1) + mfib(i‐2);

}); > console.time('fib'); > fib(35); > console.timeEnd('fib');fib: 9335ms> console.time(‘mfib'); > mfib(35); > console.timeEnd(‘mfib');fib: 1ms> console.time(‘mfib'); > mfib(1000); > console.timeEnd(‘mfib');fib: 3ms

Walking the DOM Treevar walk = function (elt, f) {

f(elt);var child = elt.firstElementChild;while (child) {

walk(child, f);child = child.nextElementSibling;

}}

var filter = function(elt, f) {var result = [];walk(elt, function (x) {

if (f(x)) result.push(x);});return result;

}

> filter(document.body, function (e) { return e.tagName === 'DIV'; }) 

Walking the DOM TreeElement.prototype.forEach = function (f) {

f(this);var child = this.firstElementChild;while (child) {

child.forEach(f);child = child.nextElementSibling;

}}

var filter = function(a, f) {var result = [];a.forEach(function (x) {

if (f(x)) result.push(x);});return result;

}

> filter(document.body, function (e) { return e.tagName === 'DIV'; }) 

Showing DOM Structure(revisited)

Walking the DOM Treefunction walk(elt, meta_parent) {

var meta_elt = make_meta(elt, meta_parent);var child = elt.firstElementChild;while (child) {

walk(child, meta_elt);child = child.nextElementSibling;

}           }

var walk = function(elt, f, meta_parent) {var meta_elt = f(elt);meta_parent.appendChild (meta_elt);var child = elt.firstElementChild;while (child) {

walk(child, f, meta_elt);child = child.nextElementSibling;

}return parent;

};

Bef

ore

Afte

r

Walking the DOM Treefunction walk(elt, meta_parent) {

var meta_elt = make_meta(elt, meta_parent);var child = elt.firstElementChild;while (child) {

walk(child, meta_elt);child = child.nextElementSibling;

}           }

var walk = function(elt, f, meta_parent) {var meta_elt = f(elt);meta_parent.appendChild (meta_elt);var child = elt.firstElementChild;while (child) {

walk(child, f, meta_elt);child = child.nextElementSibling;

}return parent;

};

function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;     

}

function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;     

}

function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;     

}

Bef

ore

Afte

r

Walking the DOM Treefunction walk(elt, meta_parent) {

var meta_elt = make_meta(elt, meta_parent);var child = elt.firstElementChild;while (child) {

walk(child, meta_elt);child = child.nextElementSibling;

}           }

var walk = function(elt, f, meta_parent) {var meta_elt = f(elt);meta_parent.appendChild (meta_elt);var child = elt.firstElementChild;while (child) {

walk(child, f, meta_elt);child = child.nextElementSibling;

}return parent;

};

function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;     

}

function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;     

}

function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;     

}

function make_meta(elt) {var meta_elt = make_matching_element(elt);          var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover", 

function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});

meta_elt.addEventListener("mouseout", function () {

elt.style.backgroundColor = original_color;});

return meta_elt;     }

Bef

ore

Afte

r

Walking the DOM Treefunction walk_body() {

var body = document.body;var fragment = document.createDocumentFragment();walk(body, fragment);body.insertBefore(make_scroll_box(fragment), body.firstChild);

}

var walk_body = function () {var body = document.body;var fragment = document.createDocumentFragment();walk(body, make_meta, fragment);body.insertBefore(make_scroll_box(fragment), body.firstChild);

}

Bef

ore

Afte

r

Another approachvar walk = function(elt, f, meta_parent) {

var mf = memoize(function(e) {if (e === elt.parentElement) 

return meta_parent;return f(e);

});

elt.forEach(function (e) {              mf(e.parentElement).appendChild (mf(e));

});};

var memoize = function (f) {var memo = [];return function (e) {

if (memo[e.uid()] === undefined) memo[e.uid()] = f(e);

return memo[e.uid()];}

}

Element.prototype.uid = (function () {var count = 0;return function () {

var id = count++;this.uid = function () { return id; }return id;               

}            })();

Generates a unique element id foreach element

mf: Apply f to each element e if you haven’t already and store the result.

Applies f to each element e and builds the new tree.