Upcoming SlideShare
×

# Functional Patterns for the non-mathematician

4,162 views
3,933 views

Published on

Fluentconf 2014 talk:

Functional design patterns such as lenses, arrows, functors, and monads all come from category theory. To fully grok them, you’ll probably have to wade through the whitest white papers, fighting the mathematical syntax and abstract examples.

I’m hoping to demonstrate the ideas into javascript. I’ll be showing direct and practical applications for every day programming.

Published in: Technology
16 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total views
4,162
On SlideShare
0
From Embeds
0
Number of Embeds
144
Actions
Shares
0
59
0
Likes
16
Embeds 0
No embeds

No notes for slide

### Functional Patterns for the non-mathematician

1. 1. Functional Patterns for the non-mathematician
2. 2. add(4, 2) //=> 6
4. 4. add(4.4, 2.2) //=> 6.6
5. 5. var inc = new Increaser(4); inc.increaseBy(2); inc.value(); // 6
6. 6. Interfaces Properties/Laws Polymorphic Composable
7. 7. Currying
8. 8. var reverseCap = compose(capitalize, reverse) reverseCap(“hello”) //=> “Olleh” Composition
9. 9. var reverseCap = compose(capitalize, reverse) reverseCap(“hello”) //=> “Olleh” Composition
10. 10. var reverseCap = compose(capitalize, reverse)(“hello”) //=> “Olleh” Composition “hello”“olleh”“Olleh”
11. 11. compose(compose(f, g), h) == compose(f, compose(g, h)) Composition (associativity)
12. 12. compose(f, g, h) Composition (associativity)
13. 13. var i = compose(g, h) compose(f, i) Composition (associativity)
14. 14. 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}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20})
15. 15. 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}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) makePage({limit: 20}) Perfect world
16. 16. function (property, x) { return x[property]; } Getters/Setters function (property, value, x) { x[property] = value; return x; }
17. 17. Lenses over(l, f, x) view(l, x) set(l, y, x)
18. 18. 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
19. 19. 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
20. 20. 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
21. 21. if(x !== null && x !== undefined) { return f(x) } Null checking
22. 22. fmap(f, Maybe(x)) Null checking
23. 23. var fmap = function(f, mappable) { return mappable.map(f) } Null checking
24. 24. fmap(function(x) { return x.toUpperCase() }, Maybe(‘hi’)) //=> Maybe(‘HI’) fmap(function(x) { return toUpperCase(x); }, Maybe(null)) //=> Maybe(null) Null checking
25. 25. fmap(function(x) { return x.toUpperCase() }, Maybe(‘hi’)) //=> Maybe(‘HI’) fmap(function(x) { return x.toUpperCase() }, Maybe(null)) //=> Maybe(null) Null checking
26. 26. compose(fmap(f), Maybe) Null checking
27. 27. var id = function(x) { return x; } fmap(id, x) == id(x) Fmap laws (identity)
28. 28. compose(fmap(f), fmap(g)) == fmap(compose(f, g)) Fmap laws (composition)
29. 29. if(x !== null && x !== undefined) { return f(x) } else { throw ‘Some Error!’ } Error Handling
30. 30. Error Handling fmap(f, Either(‘Some error’, x))
31. 31. Either(‘need an int’, 3) //=> Right(3) fmap(function(x) { return x + 1; }, Either(‘need an int’, undefined)) //=> Left(‘need an int’) Error Handling
32. 32. Either(‘need an int’, 3) //=> Right(3) Either(‘need an int’, undefined)) //=> Left(‘need an int’) Error Handling
33. 33. 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
34. 34. 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
35. 35. compose(fmap(f), Either(‘error’)) Error Handling
36. 36. f(x, function(y) { return g(y); }); Future values
37. 37. Future values fmap(f, Promise(x))
38. 38. var p = new Promise(); fmap(function(x) { return log(reverse(x)) }, p) //=> Promise() p.resolve([1,2,3]) //=>[3, 2, 1] Future values
39. 39. Something that implements map Functor
40. 40. if(x !== null && x !== undefined) { var y = f(x) if(y !== null && y !== undefined) { return g(y) } } Nesting
41. 41. f(x, function(y) { return g(y, function(z) { return h(z) }) }) Nesting
42. 42. compose(mjoin, fmap(f)) Nesting
43. 43. 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
44. 44. 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
45. 45. compose(mjoin, fmap(g), mjoin, fmap(f)) Nesting mcompose(g, f)
46. 46. compose(mjoin, fmap(g), mjoin, fmap(f)) Nesting mcompose(g, f)
47. 47. mcompose(mcompose(f, g), h) == mcompose(f, mcompose(g, h)) mcompose(f, M) == f mcompose(M, f) == f Monad laws
48. 48. Multiple null args var notNull = function(x) { return x !== null && x !== undefined } if(notNull(x) && notNull(y)) { return f(x, y) }
49. 49. Multiple Async fn’s var 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) }) })
50. 50. liftA2(f, A(x), A(y)) Multiple values
51. 51. liftA3(f, A(x), A(y), A(z)) Multiple values
52. 52. liftA2(add, Maybe(3), Maybe(4)) //=> Maybe(7) liftA2(add, Maybe(null), Maybe(4)) //=> Maybe(null) Multiple values
53. 53. liftA2(add, Maybe(3), Maybe(4)) //=> Maybe(7) liftA2(add, Maybe(null), Maybe(4)) //=> Maybe(null) Multiple values
54. 54. 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
55. 55. // identity ap(A(id), m) == m // composition ap(ap(ap(A(compose), f), g), w) == ap(f, ap(g, w)) // homomorphism ap(A(f), A(x)) == A(f(x)) // interchange ap(u, A(x)) == ap(A(function(f) { return f(x); }), u) Applicative laws
56. 56. Accumulation reduce(function(acc, x) { return acc + x; }, 0, [1,2,3])
57. 57. Accumulation reduce(function(acc, x) { return acc * x; }, 1, [1,2,3])
58. 58. Accumulation reduce(function(acc, x) { return acc || x; }, false, [false, false, true])
59. 59. Accumulation reduce(function(acc, x) { return acc && x; }, true, [false, false, true])
60. 60. Accumulation reduce(function(acc, x) { return acc > x ? acc : x; }, 0, [12, 5, 35])
61. 61. Monoid mappend(m, m) mempty(m) mconcat([m])
62. 62. Monoid mappend(m, m) mempty(m) mconcat([m])
63. 63. mconcat([Sum(1), Sum(2), Sum(3)]) //=> Sum(6) Accumulation
64. 64. mconcat([Product(1), Product(2), Product(3)]) //=> Product(6) Accumulation
65. 65. mconcat([Max(13), Max(2), Max(9)]) //=> Max(13) Accumulation
66. 66. mconcat([Any(false), Any(false), Any(true)]) //=> Any(true) Accumulation
67. 67. mconcat([All(false), All(false), All(true)]) //=> All(false) Accumulation
68. 68. compose(mconcat, map(M)) Accumulation
69. 69. // left identity mappend(mempty, x) == x // right identity mappend(x, mempty) == x // associativity mappend(mappend(x, y), z) == mappend(x, mappend(y, z)) Monoid laws
70. 70. Combinators function(x) { return [f(x), g(x)] }
71. 71. Combinators function(x, y) { return [f(x), g(y)] }
72. 72. compose(f, g) ampersand(f, g) asterisk(f, g) first(f) second(f) Arrows
73. 73. 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
74. 74. 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
75. 75. Thanks! @drboolean https://github.com/DrBoolean/patterns_talk