Download - Functional Patterns for the non-mathematician

Transcript
Page 1: Functional Patterns for the non-mathematician

Functional Patternsfor the non-mathematician

Page 2: Functional Patterns for the non-mathematician

add(4, 2)

//=> 6

Page 3: Functional Patterns for the non-mathematician

// associativeadd(add(1, 2), 4) == add(1, add(2, 4))

// commutativeadd(4, 1) == add(1, 4)

// identityadd(n, 0) == n

// distributivemultiply(2, add(3,4)) == add(multiply(2, 3), multiply(2, 4))

Page 4: Functional Patterns for the non-mathematician

add(4.4, 2.2)

//=> 6.6

Page 5: Functional Patterns for the non-mathematician

var inc = new Increaser(4);inc.increaseBy(2);inc.value();// 6

Page 6: Functional Patterns for the non-mathematician

Interfaces

Properties/Laws

Polymorphic

Composable

Page 7: Functional Patterns for the non-mathematician

Currying

Page 8: Functional Patterns for the non-mathematician

var reverseCap = compose(capitalize, reverse)

reverseCap(“hello”)//=> “Olleh”

Composition

Page 9: Functional Patterns for the non-mathematician

var reverseCap = compose(capitalize, reverse)

reverseCap(“hello”)//=> “Olleh”

Composition

Page 10: Functional Patterns for the non-mathematician

var reverseCap = compose(capitalize, reverse)(“hello”)//=> “Olleh”

Composition“hello”

“olleh”

“Olleh”

Page 11: Functional Patterns for the non-mathematician

compose(compose(f, g), h) == compose(f, compose(g, h))

Composition(associativity)

Page 12: Functional Patterns for the non-mathematician

compose(f, g, h)

Composition(associativity)

Page 13: Functional Patterns for the non-mathematician

var i = compose(g, h)compose(f, i)

Composition(associativity)

Page 14: Functional Patterns for the non-mathematician

var getFromDb = compose(pluck('rows'), User.findAll)

var cleanUpData = compose(capitalize, pluck('name'))

var renderTemplate = TemplateEngine.render(‘users_table')

var makePage = compose(renderTemplate, map(cleanUpData), getFromDb)

makePage({limit: 20})

Page 15: Functional Patterns for the non-mathematician

var getFromDb = compose(pluck('rows'), User.findAll)

var cleanUpData = compose(capitalize, pluck('name'))

var renderTemplate = TemplateEngine.render(‘users_table')

var makePage = compose(renderTemplate, map(cleanUpData), getFromDb)

makePage({limit: 20})Perfect world

Page 16: Functional Patterns for the non-mathematician
Page 17: Functional Patterns for the non-mathematician

function (property, x) { return x[property];}

Getters/Setters

function (property, value, x) { x[property] = value; return x;}

Page 18: Functional Patterns for the non-mathematician

Lenses

over(l, f, x)

view(l, x)

set(l, y, x)

Page 19: Functional Patterns for the non-mathematician

var user = {id: 1, name: ‘Alicia'}

var L = makeLenses([‘name’])

view(L.name, user) // 'Alicia'

set(L.name, 'Ally', user) // {id: 1, name: 'Ally'}

over(L.name, toUpperCase, user) // {id: 1, name: 'ALICIA'}

Lenses

Page 20: Functional Patterns for the non-mathematician

var user = {id: 1, name: {first: ‘doris’, last: ‘day’ }}

var L = makeLenses([‘name’, ‘first’])

var firstNameChar = compose(L.name, L.first, _1)

over(firstNameChar, toUpperCase, user)//=> {id: 1, name: {first: ‘Doris’, last: ‘day’ }}

Lenses

Page 21: Functional Patterns for the non-mathematician

view(l, set(l, b, a)) == b

set(l, view(l, a), a) == a

set(l, c, set(l, b, a)) == set(l, c, a)

Lens laws

Page 22: Functional Patterns for the non-mathematician
Page 23: Functional Patterns for the non-mathematician

if(x !== null && x !== undefined) { return f(x)}

Null checking

Page 24: Functional Patterns for the non-mathematician

fmap(f, Maybe(x))

Null checking

Page 25: Functional Patterns for the non-mathematician

var fmap = function(f, mappable) { return mappable.map(f)}

Null checking

Page 26: Functional Patterns for the non-mathematician

fmap(function(x) { return x.toUpperCase() }, Maybe(‘hi’))//=> Maybe(‘HI’)

fmap(function(x) { return toUpperCase(x); }, Maybe(null))//=> Maybe(null)

Null checking

Page 27: Functional Patterns for the non-mathematician

fmap(function(x) { return x.toUpperCase() }, Maybe(‘hi’))//=> Maybe(‘HI’)

fmap(function(x) { return x.toUpperCase() }, Maybe(null))//=> Maybe(null)

Null checking

Page 28: Functional Patterns for the non-mathematician

compose(fmap(f), Maybe)

Null checking

Page 29: Functional Patterns for the non-mathematician

var id = function(x) { return x; }

fmap(id, x) == id(x)

Fmap laws(identity)

Page 30: Functional Patterns for the non-mathematician

compose(fmap(f), fmap(g)) == fmap(compose(f, g))

Fmap laws(composition)

Page 31: Functional Patterns for the non-mathematician
Page 32: Functional Patterns for the non-mathematician

if(x !== null && x !== undefined) { return f(x)} else { throw ‘Some Error!’}

Error Handling

Page 33: Functional Patterns for the non-mathematician

Error Handling

fmap(f, Either(‘Some error’, x))

Page 34: Functional Patterns for the non-mathematician

Either(‘need an int’, 3)//=> Right(3)

fmap(function(x) { return x + 1; }, Either(‘need an int’, undefined))//=> Left(‘need an int’)

Error Handling

Page 35: Functional Patterns for the non-mathematician

Either(‘need an int’, 3)//=> Right(3)

Either(‘need an int’, undefined))//=> Left(‘need an int’)

Error Handling

Page 36: Functional Patterns for the non-mathematician

fmap(function(x) { return x + 1; }, Right(2))//=> Right(3)

fmap(function(x) { return x + 1; }, Either(‘need an int’, undefined))//=> Left(‘need an int’)

Error Handling

Page 37: Functional Patterns for the non-mathematician

fmap(function(x) { return x + 1; }, Right(2))//=> Right(3)

fmap(function(x) { return x + 1; }, Left(‘need an int’))//=> Left(‘need an int’)

Error Handling

Page 38: Functional Patterns for the non-mathematician

compose(fmap(f), Either(‘error’))

Error Handling

Page 39: Functional Patterns for the non-mathematician
Page 40: Functional Patterns for the non-mathematician

f(x, function(y) {return g(y);

});

Future values

Page 41: Functional Patterns for the non-mathematician

Future values

fmap(f, Promise(x))

Page 42: Functional Patterns for the non-mathematician

var p = new Promise();fmap(function(x) { return log(reverse(x)) }, p)//=> Promise()

p.resolve([1,2,3])//=>[3, 2, 1]

Future values

Page 43: Functional Patterns for the non-mathematician

Something that implements map

Functor

Page 44: Functional Patterns for the non-mathematician
Page 45: Functional Patterns for the non-mathematician

if(x !== null && x !== undefined) { var y = f(x) if(y !== null && y !== undefined) { return g(y) }}

Nesting

Page 46: Functional Patterns for the non-mathematician

f(x, function(y) {return g(y, function(z) {

return h(z)})

})

Nesting

Page 47: Functional Patterns for the non-mathematician

compose(mjoin, fmap(f))

Nesting

Page 48: Functional Patterns for the non-mathematician

var getField = compose(Maybe, document.querySelector)var getValue = compose(Maybe, pluck(‘value’))

var greet = compose(fmap(fmap(concat(‘hello’))), fmap(getValue), getField)greet(‘#name’)//=> Maybe(Maybe(‘hello chris’))

var greet = compose(fmap(concat(‘hello’)), mjoin, fmap(getValue), getField)greet(‘#name’)//=> Maybe(‘hello chris’)

Nesting

Page 49: Functional Patterns for the non-mathematician

var getField = compose(Maybe, document.querySelector)var getValue = compose(Maybe, pluck(‘value’))

var greet = compose(fmap(fmap(concat(‘hello’))), fmap(getValue), getField)greet(‘#name’)//=> Maybe(Maybe(‘hello chris’))

var greet = compose(fmap(concat(‘hello’)), mjoin, fmap(getValue), getField)greet(‘#name’)//=> Maybe(‘hello chris’)

Nesting

Page 50: Functional Patterns for the non-mathematician

compose(mjoin, fmap(g), mjoin, fmap(f))

Nesting

mcompose(g, f)

Page 51: Functional Patterns for the non-mathematician

compose(mjoin, fmap(g), mjoin, fmap(f))

Nesting

mcompose(g, f)

Page 52: Functional Patterns for the non-mathematician

mcompose(mcompose(f, g), h) == mcompose(f, mcompose(g, h))

mcompose(f, M) == f

mcompose(M, f) == f

Monad laws

Page 53: Functional Patterns for the non-mathematician
Page 54: Functional Patterns for the non-mathematician

Multiple null argsvar notNull = function(x) { return x !== null && x !== undefined}

if(notNull(x) && notNull(y)) { return f(x, y)}

Page 55: Functional Patterns for the non-mathematician

Multiple Async fn’svar y,z;

f(x, function(result) { y = result;

if(z) {return h(y, z)

})})

g(x, function(result) { z = result;

if(y) {return h(y, z)

})})

Page 56: Functional Patterns for the non-mathematician

liftA2(f, A(x), A(y))

Multiple values

Page 57: Functional Patterns for the non-mathematician

liftA3(f, A(x), A(y), A(z))

Multiple values

Page 58: Functional Patterns for the non-mathematician

liftA2(add, Maybe(3), Maybe(4))//=> Maybe(7)

liftA2(add, Maybe(null), Maybe(4))//=> Maybe(null)

Multiple values

Page 59: Functional Patterns for the non-mathematician

liftA2(add, Maybe(3), Maybe(4))//=> Maybe(7)

liftA2(add, Maybe(null), Maybe(4))//=> Maybe(null)

Multiple values

Page 60: Functional Patterns for the non-mathematician

var tweets_p = Http.get(‘/twitter/tweets’)var photos_p = Http.get(‘/flickr/photos’)var makeCollage = _.curry(function (tweets, photos){})

liftA2(makeCollage, tweets_p, photos_p)

Multiple values

Page 61: Functional Patterns for the non-mathematician

// identityap(A(id), m) == m

// compositionap(ap(ap(A(compose), f), g), w) == ap(f, ap(g, w))

// homomorphismap(A(f), A(x)) == A(f(x))

// interchangeap(u, A(x)) == ap(A(function(f) { return f(x); }), u)

Applicative laws

Page 62: Functional Patterns for the non-mathematician
Page 63: Functional Patterns for the non-mathematician

Accumulation

reduce(function(acc, x) {return acc + x;

}, 0, [1,2,3])

Page 64: Functional Patterns for the non-mathematician

Accumulation

reduce(function(acc, x) {return acc * x;

}, 1, [1,2,3])

Page 65: Functional Patterns for the non-mathematician

Accumulation

reduce(function(acc, x) {return acc || x;

}, false, [false, false, true])

Page 66: Functional Patterns for the non-mathematician

Accumulation

reduce(function(acc, x) {return acc && x;

}, true, [false, false, true])

Page 67: Functional Patterns for the non-mathematician

Accumulation

reduce(function(acc, x) {return acc > x ? acc : x;

}, 0, [12, 5, 35])

Page 68: Functional Patterns for the non-mathematician

Monoid

mappend(m, m)

mempty(m)

mconcat([m])

Page 69: Functional Patterns for the non-mathematician

Monoid

mappend(m, m)

mempty(m)

mconcat([m])

Page 70: Functional Patterns for the non-mathematician

mconcat([Sum(1), Sum(2), Sum(3)])

//=> Sum(6)

Accumulation

Page 71: Functional Patterns for the non-mathematician

mconcat([Product(1), Product(2), Product(3)])

//=> Product(6)

Accumulation

Page 72: Functional Patterns for the non-mathematician

mconcat([Max(13), Max(2), Max(9)])//=> Max(13)

Accumulation

Page 73: Functional Patterns for the non-mathematician

mconcat([Any(false), Any(false), Any(true)])//=> Any(true)

Accumulation

Page 74: Functional Patterns for the non-mathematician

mconcat([All(false), All(false), All(true)])//=> All(false)

Accumulation

Page 75: Functional Patterns for the non-mathematician

compose(mconcat, map(M))

Accumulation

Page 76: Functional Patterns for the non-mathematician

// left identitymappend(mempty, x) == x

// right identitymappend(x, mempty) == x

// associativitymappend(mappend(x, y), z) == mappend(x, mappend(y,

z))

Monoid laws

Page 77: Functional Patterns for the non-mathematician
Page 78: Functional Patterns for the non-mathematician

Combinators

function(x) { return [f(x), g(x)]}

Page 79: Functional Patterns for the non-mathematician

Combinators

function(x, y) { return [f(x), g(y)]}

Page 80: Functional Patterns for the non-mathematician

compose(f, g)

ampersand(f, g)

asterisk(f, g)

first(f)

second(f)

Arrows

Page 81: Functional Patterns for the non-mathematician

first(reverse)([‘Stan’, ‘Lee']) // [‘natS’, ‘Lee’]

second(reverse)([‘Stan’, ‘Lee']) // [‘Stan’, ‘eeL’]

ampersand(reverse, toUpperCase)(‘Stan’) // [‘natS’, ‘STAN’]

asterisk(reverse, toUpperCase)([‘Stan’, ‘Lee']) // [‘natS’, ‘LEE’]

Arrows

Page 82: Functional Patterns for the non-mathematician

A(id) == id

A(compose(f, g)) == A(compose(f, A(g)))

first(A(f)) == A(first(f))

first(compose(f, g)) == compose(first(f), first(g))

compose(first(f), A(pluck(0))) == compose(A(pluck(0)), f)

compose(first(f), A(asterisk(id, g)) == compose(A(asterisk(id, g)), first(f))

compose(first(first(f)), A(assoc) == compose(A(assoc), first(f))

Arrow laws

Page 83: Functional Patterns for the non-mathematician

Thanks!

@drboolean

https://github.com/DrBoolean/patterns_talk