06 Map Reduce

Post on 15-Jan-2015

61 views 0 download

Tags:

description

Examples and concept from the excellent Clojure talk, "A monad is not a burrito." http://www.youtube.com/watch?v=46Z7Hq4fhN0

Transcript of 06 Map Reduce

Let’s talk about lambda

Why care?

NULL is troublesome The dog breeder example

var colleen, richard;!colleen = { pet: { mother: { owner: "Sarah" } }};!richard = { pet: null};

Given a person, return its pet’s mother’s owner.

function findBreeder(person) { return person.pet.mother.owner;}

function findBreeder(person) { return person.pet.mother.owner;}!>>> findBreeder(colleen);"Sarah"!>>> findBreeder(richard);Exception: "Can not read property 'mother' of undefined"

function findBreeder(person) { if (!person) { return null; }! if (!person.pet) { return null; } if (!person.pet.mother) { return null; }! return person.pet.mother.owner;}

>>> findBreeder(colleen);"Sarah"!>>> findBreeder(richard);null

LISTS are troublesome The investment broker example

Broker Clients Investment Types Markets Balance

var colin = { clients: [ { name: "Fred", investments: [ { name: "Shares", markets: [ { name: "Japan", value: 7000 }, { name: "America", value: 8888 } ] }, { name: "Gold", markets: [ { name: "China", value: 3333 }, ] } ] } ]};

Find the sum of all of an investors’s client’s investments.

sumInvestments = (clients) -> values = [] foreach client in clients: foreach investment in client.investments foreach market in investment.markets values.push(market.balance) return sum(values)

function sumInvestments (clients) { var i, j, k; var investments, markets; var value = 0;! for (i = 0; i < clients.length; i++) { investments = clients[i].investments;! for (j = 0; j < investments.length; j++) { markets = investments[j].markets;! for (k = 0; k < markets.length; k++) { value += markets[k].value } } }! return value;};

(multi-layer list iteration) vs. (null checking) !

What’s the common thread?

no code duplication !

lots of concept duplication

function call_unless_null(val, fn) { if (val !== null) { return fn(val); }! return null;}!function findBreeder(person) { return call_unless_null(person, function(person) { return call_unless_null(person.pet, function(pet) { return call_unless_null(pet.mother, function(mother) { return mother.owner; }); }); });}

>>> findBreeder(colleen);"Sarah"!>>> findBreeder(richard);null

Still too much duplication.

function reduce(iter, memo, fn) { for (var i = 0; i < iter.length; i++) { memo = fn(memo, iter[i]); }! return memo;}!function get_unless_null(obj, key) { if (obj !== null && obj !== undefined) { return obj[key]; } return null;}!function findBreeder(person) { return reduce(['pet', 'mother', ‘owner’], person, get_unless_null);}

>>> findBreeder(colleen);"Sarah"!>>> findBreeder(richard);null

function sumInvestments(clients) { var values;! values = flat_map(clients, function(client) { return flat_map(client.investments, function(investment) { return flat_map(investment.markets, function(market) { return market.value; }); }); });! return sum(values);};

function map(iter, fn) { var out = [], val;! for (var i = 0; i < iter.length; i++) { out[i] = fn(iter[i]); }! return out;}!function flat_map(iter, fn) { iter = map(iter, fn); return reduce(iter, [], function(memo, item) { return memo.concat(item); });}!function sum(list) { return reduce(list, 0, function(memo, num) { return memo + num; });}

function sumInvestments(clients) { var v, fn;! fn = function(arr, key) { return flat_map(arr, function(item) { return get_unless_null(item, key); }); };! v = reduce(clients, ['investments', 'markets', 'value'], fn); return sum(v);};

What have we accomplished?

function sumInvestments (clients) { var i, j, k; var investments, markets; var value = 0;! for (i = 0; i < clients.length; i++) { investments = clients[i].investments;! for (j = 0; j < investments.length; j++) { markets = investments[j].markets;! for (k = 0; k < markets.length; k++) { value += markets[k].value } } }! return value};!function sumInvestments(clients) { var v;! v = reduce(clients, ['investments', 'markets', 'value'], function(arr, key) { return flat_map(arr, function(item) { return item[key]; }); });! return sum(v);};

ugly

awesome

function findBreeder(person) { if (!person) { return null; }! if (!person.pet) { return null; } if (!person.pet.mother) { return null; }! return person.pet.mother.owner;}!!!function findBreeder(person) { return reduce(get_unless_null, person, ['pet', 'mother', 'owner']);}

ugly

awesome

Concept duplication is just masked code duplication

Repeating patterns are hint

Higher-order functions make all this possible