SlideShare a Scribd company logo
You will see 
• Lots of functional JavaScript code 
• Benefits and drawbacks 
• Functional Optimizations 
• Lots of unexplained type signatures
You won’t see 
• Detailed explanations of the code 
• Definitions for functional constructs 
• Extensive performance analysis
59 // src :: FlickrItem -> URL 
60 var src = compose(_.get('m'), _.get('media')); 
61 
62 // srcs :: FlickrSearch -> [URL] 
63 var srcs = compose(map(src), _.get('items')); 
64 
65 // images :: FlickrSearch -> [DOM] 
66 var images = compose(map(imageTag), srcs); 
67 
68 // tags :: FlickrSearch -> [DOM] 
69 var tags = compose(toP, _.countBy(_.id), _.filter(_.isEmpty), chain(split(‘ ‘))); 
70 
71 // imagesAndTags :: Tuple [DOM] [DOM] 
72 var imagesAndTags = liftA2(Tuple, images, tags); 
73 
74 // widget :: String -> PictureBox 
75 var widget = compose(PictureBox, map(imagesAndTags), getJSON, url); 
76 
77 /////////////////////////////////////////////////////////////////////////////////// 
78 
79 mconcat([widget('cats'), widget('dogs')]).fork(log, function(x){ 
80 compose(setHtml($('#flickr')), _.first)(x) 
81 compose(setHtml($(‘#tag_cloud')), _.last)(x) 
82 }); 
83 });
style provides benefits. You should do it whenever it is convenient, and
Questions 
• Why might one do this? 
• What problems are there? 
• Is it performant? 
• Is it “production ready?”
Pointfree
We can curry 
var replace = curry(function(regex, x, replaceable) { 
return replaceable.replace(regex, x); 
}); 
var squish = replace(/s+/g, ''); 
squish("I like to move it move it"); // Iliketomoveitmoveit
We can compose 
var wackyText = compose(capitalize, reverse, squish) 
wackyText(“turtle power") // Rewopeltrut
Pointfree 
var clientApp = compose(render, doThings, httpGet(‘/posts')) 
var serverApp = compose(sendJSON, doThings, Db.all(‘posts’)) 
var shellApp = compose(display, doThings, prompt("what's up?"))
Pointfree 
httpGet('/post/2', function(json){ 
renderPost(json); 
});
Pointfree 
httpGet('/post/2', function(json, err){ 
renderPost(json, err); 
});
Pointfree 
httpGet(‘/post/2’, renderPost)
Pointfree 
httpGet(‘/post/2’, renderPost) 
GOOD
Pointfree 
var goodArticles = function(articles) { 
return _.filter(articles, function(article){ 
return _.isDefined(article); 
}) 
}
Pointfree 
var goodArticles = function(articles) { 
return _.filter(articles, function(article){ 
return _.isDefined(article); 
}) 
} 
var goodArticles = filter(isDefined)
Pointfree 
var goodArticles = function(articles) { 
return _.filter(articles, function(article){ 
return _.isDefined(article); 
}) 
} 
var goodArticles = filter(isDefined)
Pointfree 
var goodArticles = function(articles) { 
return _.filter(articles, function(article){ 
return _.isDefined(article); 
}) 
} 
var goodArticles = filter(isDefined) 
GOOD
Pointfree 
var getChildren = function(el) { 
return el.childNodes; 
} 
var getAllChildren = function(els) { 
return _.map(els, function(el) { 
return getChildren(el); 
}); 
}
Pointfree 
var getChildren = function(el) { 
return el.childNodes; 
} 
var getAllChildren = function(els) { 
return _.map(els, function(el) { 
return getChildren(el); 
}); 
} 
var getChildren = get('childNodes') 
var getAllChildren = map(getChildren)
Pointfree 
var getChildren = function(el) { 
return el.childNodes; 
} 
var getAllChildren = function(els) { 
return _.map(els, function(el) { 
return getChildren(el); 
}); 
} 
var getChildren = get('childNodes') 
var getAllChildren = map(getChildren)
Pointfree 
var getChildren = function(el) { 
return el.childNodes; 
} 
var getAllChildren = function(els) { 
return _.map(els, function(el) { 
return getChildren(el); 
}); 
} 
var getChildren = get('childNodes') 
var getAllChildren = map(getChildren) 
GOOD
Pointfree 
var grandChildren = function(selector) { 
var el = document.querySelector(selector); 
var children = getChildren(el); 
return map(getChildren, children); 
} 
var grandChildren = compose( map(getChildren) 
, getChildren 
, document.querySelector 
)
Pointfree 
var grandChildren = function(selector) { 
var el = document.querySelector(selector); 
var children = getChildren(el); 
return map(getChildren, children); 
} 
var grandChildren = compose( map(getChildren) 
, getChildren 
, document.querySelector 
) 
GOOD
Pointfree 
var video = { src: 'http://youtube.com?v=23423' 
, description: 'family matters ep1' 
, screenshots: [ { url: 'i.ytimg.com/OrIxGlo.webp', size: ‘120x120' } 
, { url: 'i.ytimg.com/3rAxRdb.webp', size: ‘1020x764' } 
] 
} 
var thumb = compose(_.first, _.get(‘screenshots')) 
var thumbUrl = compose(_.get('url'), thumb) 
var thumbWithHost = compose(concat('http://youtube.com'), thumbUrl) 
thumbWithHost(video) 
// http://youtube.com/i.ytimg.com/OrIxaBJ9Glo.webp
Pointfree 
var video = { src: 'http://youtube.com?v=23423' 
, description: 'family matters ep1' 
, screenshots: [ { url: 'i.ytimg.com/OrIxGlo.webp', size: ‘120x120' } 
, { url: 'i.ytimg.com/3rAxRdb.webp', size: ‘1020x764' } 
] 
} 
var thumbUrl = compose(_.get('url'), thumb) 
var thumb = compose(_.first, _.get(‘screenshots')) 
var thumbWithHost = compose(concat('http://youtube.com'), thumbUrl) 
thumbWithHost(video) 
// TypeError
Pointfree 
var video = { src: 'http://youtube.com?v=23423' 
, description: 'family matters ep1' 
, screenshots: [ { url: 'i.ytimg.com/OrIxGlo.webp', size: ‘120x120' } 
, { url: 'i.ytimg.com/3rAxRdb.webp', size: ‘1020x764' } 
] 
} 
var thumbUrl = compose(_.get('url'), thumb) 
var thumb = compose(_.first, _.get(‘screenshots')) 
var thumbWithHost = compose(concat('http://youtube.com'), thumbUrl) 
thumbWithHost(video) 
// TypeError 
Meh
First Class? 
["10", "50", "20"].map(function(x){ return parseInt(x); }); 
// [10, 50, 20] 
["10", "50", "20"].map(parseInt); 
// [10, NaN, NaN]
First Class? 
["10", "50", "20"].map(function(x){ return parseInt(x); }); 
// [10, 50, 20] 
["10", "50", "20"].map(parseInt); 
// [10, NaN, NaN] 
// "The Madness of King JavaScript" by Reg Braithwaite (raganwald) 
BAD
First Class? 
var phone = { 
dial: function(x){ console.log("DIALING: ", this.format(x)); }, 
format: function(n) { return n.replace(/-/g, '') } 
}; 
var numbers = ["234-3535-2342", “1-653-124-8321"]; 
numbers.map(function(x){ return phone.dial(x); }); 
// DIALING: 23435352342 
// DIALING: 16531248321
First Class? 
var phone = { 
dial: function(x){ console.log("DIALING: ", this.format(x)); }, 
format: function(n) { return n.replace(/-/g, '') } 
}; 
var numbers = ["234-3535-2342", “1-653-124-8321"]; 
numbers.map(function(x){ return phone.dial(x); }); 
// DIALING: 23435352342 
// DIALING: 16531248321 
numbers.map(phone.dial);
First Class? 
var phone = { 
dial: function(x){ console.log("DIALING: ", this.format(x)); }, 
format: function(n) { return n.replace(/-/g, '') } 
}; 
var numbers = ["234-3535-2342", “1-653-124-8321"]; 
numbers.map(function(x){ return phone.dial(x); }); 
// DIALING: 23435352342 
// DIALING: 16531248321 
numbers.map(phone.dial); 
// TypeError: Object #<Object> has no method 'format'
First Class? 
var phone = { 
dial: function(x){ console.log("DIALING: ", this.format(x)); }, 
format: function(n) { return n.replace(/-/g, '') } 
}; 
var numbers = ["234-3535-2342", “1-653-124-8321"]; 
numbers.map(function(x){ return phone.dial(x); }); 
// DIALING: 23435352342 
// DIALING: 16531248321 
numbers.map(phone.dial.bind(phone)); 
// DIALING: 23435352342 
// DIALING: 16531248321
First Class? 
var phone = { 
dial: function(x){ console.log("DIALING: ", this.format(x)); }, 
format: function(n) { return n.replace(/-/g, '') } 
}; 
var numbers = ["234-3535-2342", “1-653-124-8321"]; 
numbers.map(function(x){ return phone.dial(x); }); 
// DIALING: 23435352342 
// DIALING: 16531248321 
numbers.map(phone.dial.bind(phone)); 
// DIALING: 23435352342 
// DIALING: 16531248321 
BAD
//+ render :: [Tag] -> DOM 
var render = compose($(‘#tag-cloud').html, tagView, addFontSizes) 
//+ tagCloud :: Params -> Future(DOM) 
var tagCloud = compose(map(render), httpGet('/tags'))
//+ setHtml :: String -> Html -> IO(DOM) 
var setHtml = curry(function(selector, h) { 
return IO(function() { return $(selector).html(h); }); 
}); 
//+ render :: [Tag] -> IO(DOM) 
var render = compose(setHtml(‘#tag-cloud'), tagView, addFontSizes) 
//+ tagCloud :: Params -> Future(IO(DOM)) 
var tagCloud = compose(map(render), httpGet('/tags'))
Pointfree 
• Removes unnecessary code 
• High level declarative apps 
• Encourages generic code 
• Encourages purity
Pointfree 
• Order of definition matters 
• Weird interop with imperative community (impure, 
swiss army fn’s, & ‘this’)
Demos
Typeclass
Typeclass 
promise.then(function(x){ return x + 1 }); // Promise(2) 
[1].map(function(x) { return x + 1 }); // [2] 
event_stream.subscribe(function(x) { return x + 1 }) // EventStream(2)
Typeclass 
var Container = function(val) { 
this.val = val; 
} 
Container.prototype.of = function(x) { 
return new Container(x); 
} 
Container.prototype.chain = function(f) { 
return f(this.val); 
};
Typeclass 
We can map over them 
(a -> b) -> M(a) -> M(b)
Typeclass 
We can map over them 
(a -> b) -> M(a) -> M(b) 
promise.map(function(x){ return x + 1 }); // Promise(2) 
[1].map(function(x) { return x + 1 }); // [2] 
event_stream.map(function(x) { return x + 1 }) // EventStream(2) 
Just(1).map(function(x) { return x + 1 }) // Just(2) 
Nothing.map(function(x) { return x + 1 }) // Nothing 
IO(1).map(function(x) { return x + 1 }) // IO(2)
Typeclass 
We can flatten/un-nest them 
M(M(a)) -> M(a)
Typeclass 
We can flatten/un-nest them 
M(M(a)) -> M(a) 
[['hello']] -> ['hello'] 
Just(Just(true)) -> Just(true)
Typeclass 
We can apply functions within them 
M(a -> b) -> M(a) -> M(b)
Typeclass 
We can apply functions within them 
M(a -> b) -> M(a) -> M(b) 
var finished = curry(function(click, anim) { alert(“Finished!"); }); 
EventStream.of(finished).ap(button_clicks).ap(animation_done);
Typeclass 
We can combine them 
M(a) -> M(a) -> M(a)
Typeclass 
We can combine them 
M(a) -> M(a) -> M(a) 
Api.get(‘/unstarred’).concat(Api.get('/starred')) 
// Future([Item])
Typeclass 
We can compose them 
M(N(a)) -> MN(a)
Typeclass 
We can compose them 
M(N(a)) -> MN(a) 
//+ askQuestion :: IO(Maybe(String)) 
compose(map(map(storeResponse)), askQuestion) 
//+ askQuestion :: Compose(IO(Maybe(String))) 
compose(map(storeResponse), Compose, askQuestion)
Typeclass 
We can commute them 
M(N(a)) -> N(M(a))
Typeclass 
We can commute them 
M(N(a)) -> N(M(a)) 
compose(sequenceA, map(readFile)) 
// Future([String])
Typeclass 
We can derive lots of this! 
derive(MyType, [Functor, Applicative, Foldable]) 
*https://github.com/fantasyland/fantasy-land/pull/66
Typeclass 
//+ validate :: UserAttrs -> Either([Error], UserAttrs) 
//+ saveUser :: UserAttrs -> Future(User) 
//+ emailPassword :: User -> Future(Email) 
//+ saveThenEmail :: UserAttrs -> Future(Email) 
var saveThenEmail = compose(chain(emailPassword), saveUser) 
//+ createUser :: UserAttrs -> Either([Error], Future(Email)) 
var createUser = compose(map(saveThenEmail), validate)
Typeclass 
//+ validate :: UserAttrs -> Either([Error], UserAttrs) 
//+ saveUser :: UserAttrs -> Future(User) 
//+ emailPassword :: User -> Future(Email) 
//+ saveThenEmail :: UserAttrs -> Future(Email) 
var saveThenEmail = compose(chain(emailPassword), saveUser) 
//+ createUser :: UserAttrs -> Either([Error], Future(Email)) 
var createUser = compose(map(saveThenEmail), validate) 
GOOD
GOOD
Typeclass 
//+ lookup :: String -> {String: a} -> a|null 
var lookup = curry(function(x, obj) { 
return obj[x]; 
}) 
var upperName = compose(toUpperCase, lookup(‘name')) 
upperName({name: “Tori Amos"}) // “TORI AMOS” 
upperName({first_name: "Tori", last_name: “Spelling"}) // BOOM!
Typeclass 
//+ safeLookup :: String -> {String: a} -> Maybe(a) 
var safeLookup = curry(function(x, obj) { 
return Maybe.fromNullable(obj[x]); 
}); 
var upperName = compose(map(toUpperCase), safeLookup(‘name')) 
upperName({name: “Tori Amos”}) 
// Just(“TORI AMOS”) 
upperName({first_name: "Tori", last_name: “Spelling”}) 
// Nothing
Typeclass 
//+ safeLookup :: String -> {String: a} -> Maybe(a) 
var safeLookup = curry(function(x, obj) { 
return Maybe.fromNullable(obj[x]); 
}); 
var upperName = compose(map(toUpperCase), safeLookup(‘name')) 
upperName({name: “Tori Amos”}) 
// Just(“TORI AMOS”) 
upperName({first_name: "Tori", last_name: “Spelling”}) 
// Nothing 
GOOD
GOOD
Typeclass 
//+ readFile :: Future(Maybe(String)) 
//+ lipogram :: String -> Future(Maybe(String)) 
var lipogram = compose(map(map(replace(/e/ig))), readFile);
Typeclass 
//+ readFile :: String -> Compose(Future(Maybe(String))) 
var readFile = compose(Compose, _readFile) 
//+ lipogram :: String -> Compose(Future(Maybe(String))) 
var lipogram = compose(map(replace(/e/ig)), readFile);
Typeclass 
var WebApp = ReaderT(StateT(Future))
Typeclass 
Meh 
var WebApp = ReaderT(StateT(Future))
Typeclass 
do 
a <- Just 3 
b <- Just 1 
return a + b 
Just(3).chain(function(a) { 
return Just(1).chain(function(b) { 
return Maybe.of(a + b); 
}); 
}; 
Haskell 
JavaScript
Typeclass 
do 
a <- Just 3 
b <- Just 1 
return a + b 
Haskell 
JavaScript liftM2(add, Just(3), Just(1))
Typeclass 
do 
post_id <- param "id" 
post <- lift $ findPost post_id 
return (toJSON post) 
Haskell 
(lift . (fmap toJSON) . findPost) =<< param "id" 
JavaScript 
chain(compose(lift, map(toJSON), findPost), param(‘id'))
Typeclass 
do 
post_id <- param "id" 
post <- lift $ findPost post_id 
return (toJSON post) 
Haskell 
(lift . (fmap toJSON) . findPost) =<< param "id" 
JavaScript 
chain(compose(lift, map(toJSON), findPost), param(‘id')) 
Meh
Typeclass 
do 
post_id <- param "id" 
post <- lift $ findPost post_id 
return (toJSON post) 
Haskell 
(lift . (fmap toJSON) . findPost) =<< param "id" 
JavaScript 
chain(compose(lift, map(toJSON) findPost), param(‘id'))
Typeclass 
do 
post_id <- param "id" 
post <- lift $ findPost post_id 
return (toJSON post) 
Haskell 
(lift . (fmap toJSON) . findPost) =<< param "id" 
JavaScript 
chain(compose(WebApp.lift, map(toJSON) findPost), param(‘id'))
Typeclass 
//+ savePhotos :: [Path] -> Future([Photo]) 
var savePhotos = compose(traverse(uploadPhoto), map(toBlob)) 
//+ gift :: Future(User) -> Maybe(Future(Card)) 
var gift = compose(traverse(sendCard, Maybe.of), map(_.get("birthday"))
Typeclass 
//+ savePhotos :: [Path] -> Future([Photo]) 
var savePhotos = compose(traverse(uploadPhoto), map(toBlob)) 
//+ gift :: Future(User) -> Maybe(Future(Card)) 
var gift = compose(traverse(sendCard, Maybe.of), map(_.get("birthday")) 
BAD
Typeclass 
• Universal interface (across languages) 
• Generic programs/libraries 
• Safer programs 
• Theory backed 
• Intuition
Typeclass 
• Missing polymorphic “point” 
• Working ‘blind’ with stacked containers 
• No syntactic sugar
Demos
Shortcut Fusion 
// g :: forall b. (t -> b -> b) -> b -> b 
reduce(c, n, build(g)) = g(c, n)
Shortcut Fusion 
//build :: (forall b. (a -> b -> b) -> b -> b) -> [a] 
var build = function(g){ 
return g(concat, []); 
} 
//+ map :: (a -> b) -> [a] -> [b] 
var map = curry(function(f, xs){ 
return build(function(c, n){ 
return reduce(function(acc, x){ return c(f(x), acc); }, n, xs); 
}); 
});
Shortcut Fusion 
var sum = reduce(add, 0); 
var sqr = function(x) {return x * x } 
var sumSqs = compose(sum, map(sqr)) 
// reduce(function(acc, x){ return add(sqr(x), acc) }, 0);
Compile while you 
compose 
//+ doorman :: [User] -> User 
var doorman = compose(first, filter(gte(21)), map(_.get('age')));
var addTwenty = memoize(function(x) { 
return x + 20; 
}) 
Memoization
Memoization 
var addTwenty = memoize(function(x) { 
return x + 20; 
}) 
addTwenty(10) // 30 
addTwenty(10) // 30 (didn't run) 
addTwenty(11) // 31
Memoization 
var getPosts = memoize(function(id) { 
return new Future(function(rej, res) { 
$.getJSON('/posts/'+id, res); 
}); 
});
Memoization 
var getPosts = memoize(function(id) { 
return new Future(function(rej, res) { 
$.getJSON('/posts/'+id, res); 
}); 
}); 
getPosts(2) // Future 
getPosts(2) // Future (didn't run) 
getPosts(3) // Future
Memoization 
var pQuery = $.toIO() 
pQuery(".troll") // IO(function(){ return $(".troll") }) 
pQuery.runIO() // [Dom, Dom] 
pQuery.runIO() // [Dom, Dom, Dom]
Parallel code 
foldMap(Sum, [2, 3, 5])
Parallel code 
liftA3(fn, A1, A2, A3)
Parallel code 
var longCalc // Int -> Future(Int) 
var collectResults = curry(function(rslt1, rslt2, rslt3){}) 
liftA3(collectResults, longCalc(20), longCalc(30), longCalc(10))
Parallel code 
var hasName // Attrs -> Validation 
liftA3(save, hasName, hasEmail, hasPhone)
THANKS! 
@drboolean

More Related Content

What's hot

Javascript essential-pattern
Javascript essential-patternJavascript essential-pattern
Javascript essential-pattern
偉格 高
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Stripe
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
MongoDB
 
An Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackAn Elephant of a Different Colour: Hack
An Elephant of a Different Colour: Hack
Vic Metcalfe
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeMongoDB
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)MongoSF
 
PhoneGap: Local Storage
PhoneGap: Local StoragePhoneGap: Local Storage
PhoneGap: Local Storage
Ivano Malavolta
 
Coscup2021-rust-toturial
Coscup2021-rust-toturialCoscup2021-rust-toturial
Coscup2021-rust-toturial
Wayne Tsai
 
Malli: inside data-driven schemas
Malli: inside data-driven schemasMalli: inside data-driven schemas
Malli: inside data-driven schemas
Metosin Oy
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
Bruno Scopelliti
 
MiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptMiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScript
Caridy Patino
 
Rust ⇋ JavaScript
Rust ⇋ JavaScriptRust ⇋ JavaScript
Rust ⇋ JavaScript
Ingvar Stepanyan
 
Coscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usageCoscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usage
Wayne Tsai
 
Report: Avalanche 'very likely' to host outdoor game at Coors Field
Report: Avalanche 'very likely' to host outdoor game at Coors FieldReport: Avalanche 'very likely' to host outdoor game at Coors Field
Report: Avalanche 'very likely' to host outdoor game at Coors Field
fabulouspsychop39
 
Lambda expressions in C++
Lambda expressions in C++Lambda expressions in C++
Lambda expressions in C++
Dimitrios Platis
 
Зависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим ТалдыкинЗависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим Талдыкин
Юрий Сыровецкий
 
Test driven game development silly, stupid or inspired?
Test driven game development   silly, stupid or inspired?Test driven game development   silly, stupid or inspired?
Test driven game development silly, stupid or inspired?Eric Smith
 
Designing with malli
Designing with malliDesigning with malli
Designing with malli
Metosin Oy
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With Clojure
Metosin Oy
 
Test Driven Cocos2d
Test Driven Cocos2dTest Driven Cocos2d
Test Driven Cocos2d
Eric Smith
 

What's hot (20)

Javascript essential-pattern
Javascript essential-patternJavascript essential-pattern
Javascript essential-pattern
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
An Elephant of a Different Colour: Hack
An Elephant of a Different Colour: HackAn Elephant of a Different Colour: Hack
An Elephant of a Different Colour: Hack
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
 
PhoneGap: Local Storage
PhoneGap: Local StoragePhoneGap: Local Storage
PhoneGap: Local Storage
 
Coscup2021-rust-toturial
Coscup2021-rust-toturialCoscup2021-rust-toturial
Coscup2021-rust-toturial
 
Malli: inside data-driven schemas
Malli: inside data-driven schemasMalli: inside data-driven schemas
Malli: inside data-driven schemas
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
MiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptMiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScript
 
Rust ⇋ JavaScript
Rust ⇋ JavaScriptRust ⇋ JavaScript
Rust ⇋ JavaScript
 
Coscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usageCoscup2021 - useful abstractions at rust and it's practical usage
Coscup2021 - useful abstractions at rust and it's practical usage
 
Report: Avalanche 'very likely' to host outdoor game at Coors Field
Report: Avalanche 'very likely' to host outdoor game at Coors FieldReport: Avalanche 'very likely' to host outdoor game at Coors Field
Report: Avalanche 'very likely' to host outdoor game at Coors Field
 
Lambda expressions in C++
Lambda expressions in C++Lambda expressions in C++
Lambda expressions in C++
 
Зависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим ТалдыкинЗависимые типы в GHC 8. Максим Талдыкин
Зависимые типы в GHC 8. Максим Талдыкин
 
Test driven game development silly, stupid or inspired?
Test driven game development   silly, stupid or inspired?Test driven game development   silly, stupid or inspired?
Test driven game development silly, stupid or inspired?
 
Designing with malli
Designing with malliDesigning with malli
Designing with malli
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With Clojure
 
Test Driven Cocos2d
Test Driven Cocos2dTest Driven Cocos2d
Test Driven Cocos2d
 

Viewers also liked

Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
Brian Lonsdorf
 
Millionways
MillionwaysMillionways
Millionways
Brian Lonsdorf
 
Functional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptFunctional Reactive Programming in Javascript
Functional Reactive Programming in Javascript
Brian Lonsdorf
 
Functional js class
Functional js classFunctional js class
Functional js class
Brian Lonsdorf
 
Liftin every day
Liftin every dayLiftin every day
Liftin every day
Brian Lonsdorf
 
Js for learning
Js for learningJs for learning
Js for learning
Brian Lonsdorf
 
Functional Patterns for the non-mathematician
Functional Patterns for the non-mathematicianFunctional Patterns for the non-mathematician
Functional Patterns for the non-mathematician
Brian Lonsdorf
 

Viewers also liked (8)

Oh Composable World!
Oh Composable World!Oh Composable World!
Oh Composable World!
 
Millionways
MillionwaysMillionways
Millionways
 
Functional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptFunctional Reactive Programming in Javascript
Functional Reactive Programming in Javascript
 
Functional js class
Functional js classFunctional js class
Functional js class
 
Liftin every day
Liftin every dayLiftin every day
Liftin every day
 
Js for learning
Js for learningJs for learning
Js for learning
 
Underscore
UnderscoreUnderscore
Underscore
 
Functional Patterns for the non-mathematician
Functional Patterns for the non-mathematicianFunctional Patterns for the non-mathematician
Functional Patterns for the non-mathematician
 

Similar to Fact, Fiction, and FP

Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
Visual Engineering
 
Webgl para JavaScripters
Webgl para JavaScriptersWebgl para JavaScripters
Webgl para JavaScriptersgerbille
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
Alex Payne
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScript
Luis Atencio
 
Javascript
JavascriptJavascript
Javascript
Vlad Ifrim
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说Ting Lv
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
名辰 洪
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Libraries
jeresig
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Tsuyoshi Yamamoto
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
Guy Royse
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
David Padbury
 
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Doris Chen
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
Ankit Rastogi
 
Intro to Javascript
Intro to JavascriptIntro to Javascript
Intro to Javascript
Anjan Banda
 
Cpp tutorial
Cpp tutorialCpp tutorial
Cpp tutorial
Vikas Sharma
 

Similar to Fact, Fiction, and FP (20)

Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
 
Webgl para JavaScripters
Webgl para JavaScriptersWebgl para JavaScripters
Webgl para JavaScripters
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScript
 
Javascript
JavascriptJavascript
Javascript
 
Intro to HTML5
Intro to HTML5Intro to HTML5
Intro to HTML5
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Libraries
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Intro to Javascript
Intro to JavascriptIntro to Javascript
Intro to Javascript
 
Cpp tutorial
Cpp tutorialCpp tutorial
Cpp tutorial
 

Recently uploaded

GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
Bhaskar Mitra
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 

Recently uploaded (20)

GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 

Fact, Fiction, and FP

  • 1.
  • 2. You will see • Lots of functional JavaScript code • Benefits and drawbacks • Functional Optimizations • Lots of unexplained type signatures
  • 3. You won’t see • Detailed explanations of the code • Definitions for functional constructs • Extensive performance analysis
  • 4.
  • 5. 59 // src :: FlickrItem -> URL 60 var src = compose(_.get('m'), _.get('media')); 61 62 // srcs :: FlickrSearch -> [URL] 63 var srcs = compose(map(src), _.get('items')); 64 65 // images :: FlickrSearch -> [DOM] 66 var images = compose(map(imageTag), srcs); 67 68 // tags :: FlickrSearch -> [DOM] 69 var tags = compose(toP, _.countBy(_.id), _.filter(_.isEmpty), chain(split(‘ ‘))); 70 71 // imagesAndTags :: Tuple [DOM] [DOM] 72 var imagesAndTags = liftA2(Tuple, images, tags); 73 74 // widget :: String -> PictureBox 75 var widget = compose(PictureBox, map(imagesAndTags), getJSON, url); 76 77 /////////////////////////////////////////////////////////////////////////////////// 78 79 mconcat([widget('cats'), widget('dogs')]).fork(log, function(x){ 80 compose(setHtml($('#flickr')), _.first)(x) 81 compose(setHtml($(‘#tag_cloud')), _.last)(x) 82 }); 83 });
  • 6.
  • 7. style provides benefits. You should do it whenever it is convenient, and
  • 8. Questions • Why might one do this? • What problems are there? • Is it performant? • Is it “production ready?”
  • 10. We can curry var replace = curry(function(regex, x, replaceable) { return replaceable.replace(regex, x); }); var squish = replace(/s+/g, ''); squish("I like to move it move it"); // Iliketomoveitmoveit
  • 11. We can compose var wackyText = compose(capitalize, reverse, squish) wackyText(“turtle power") // Rewopeltrut
  • 12. Pointfree var clientApp = compose(render, doThings, httpGet(‘/posts')) var serverApp = compose(sendJSON, doThings, Db.all(‘posts’)) var shellApp = compose(display, doThings, prompt("what's up?"))
  • 13.
  • 14.
  • 15.
  • 17. Pointfree httpGet('/post/2', function(json, err){ renderPost(json, err); });
  • 20.
  • 21. Pointfree var goodArticles = function(articles) { return _.filter(articles, function(article){ return _.isDefined(article); }) }
  • 22. Pointfree var goodArticles = function(articles) { return _.filter(articles, function(article){ return _.isDefined(article); }) } var goodArticles = filter(isDefined)
  • 23. Pointfree var goodArticles = function(articles) { return _.filter(articles, function(article){ return _.isDefined(article); }) } var goodArticles = filter(isDefined)
  • 24. Pointfree var goodArticles = function(articles) { return _.filter(articles, function(article){ return _.isDefined(article); }) } var goodArticles = filter(isDefined) GOOD
  • 25. Pointfree var getChildren = function(el) { return el.childNodes; } var getAllChildren = function(els) { return _.map(els, function(el) { return getChildren(el); }); }
  • 26. Pointfree var getChildren = function(el) { return el.childNodes; } var getAllChildren = function(els) { return _.map(els, function(el) { return getChildren(el); }); } var getChildren = get('childNodes') var getAllChildren = map(getChildren)
  • 27. Pointfree var getChildren = function(el) { return el.childNodes; } var getAllChildren = function(els) { return _.map(els, function(el) { return getChildren(el); }); } var getChildren = get('childNodes') var getAllChildren = map(getChildren)
  • 28. Pointfree var getChildren = function(el) { return el.childNodes; } var getAllChildren = function(els) { return _.map(els, function(el) { return getChildren(el); }); } var getChildren = get('childNodes') var getAllChildren = map(getChildren) GOOD
  • 29.
  • 30. Pointfree var grandChildren = function(selector) { var el = document.querySelector(selector); var children = getChildren(el); return map(getChildren, children); } var grandChildren = compose( map(getChildren) , getChildren , document.querySelector )
  • 31. Pointfree var grandChildren = function(selector) { var el = document.querySelector(selector); var children = getChildren(el); return map(getChildren, children); } var grandChildren = compose( map(getChildren) , getChildren , document.querySelector ) GOOD
  • 32.
  • 33. Pointfree var video = { src: 'http://youtube.com?v=23423' , description: 'family matters ep1' , screenshots: [ { url: 'i.ytimg.com/OrIxGlo.webp', size: ‘120x120' } , { url: 'i.ytimg.com/3rAxRdb.webp', size: ‘1020x764' } ] } var thumb = compose(_.first, _.get(‘screenshots')) var thumbUrl = compose(_.get('url'), thumb) var thumbWithHost = compose(concat('http://youtube.com'), thumbUrl) thumbWithHost(video) // http://youtube.com/i.ytimg.com/OrIxaBJ9Glo.webp
  • 34. Pointfree var video = { src: 'http://youtube.com?v=23423' , description: 'family matters ep1' , screenshots: [ { url: 'i.ytimg.com/OrIxGlo.webp', size: ‘120x120' } , { url: 'i.ytimg.com/3rAxRdb.webp', size: ‘1020x764' } ] } var thumbUrl = compose(_.get('url'), thumb) var thumb = compose(_.first, _.get(‘screenshots')) var thumbWithHost = compose(concat('http://youtube.com'), thumbUrl) thumbWithHost(video) // TypeError
  • 35. Pointfree var video = { src: 'http://youtube.com?v=23423' , description: 'family matters ep1' , screenshots: [ { url: 'i.ytimg.com/OrIxGlo.webp', size: ‘120x120' } , { url: 'i.ytimg.com/3rAxRdb.webp', size: ‘1020x764' } ] } var thumbUrl = compose(_.get('url'), thumb) var thumb = compose(_.first, _.get(‘screenshots')) var thumbWithHost = compose(concat('http://youtube.com'), thumbUrl) thumbWithHost(video) // TypeError Meh
  • 36.
  • 37.
  • 38.
  • 39. First Class? ["10", "50", "20"].map(function(x){ return parseInt(x); }); // [10, 50, 20] ["10", "50", "20"].map(parseInt); // [10, NaN, NaN]
  • 40. First Class? ["10", "50", "20"].map(function(x){ return parseInt(x); }); // [10, 50, 20] ["10", "50", "20"].map(parseInt); // [10, NaN, NaN] // "The Madness of King JavaScript" by Reg Braithwaite (raganwald) BAD
  • 41. First Class? var phone = { dial: function(x){ console.log("DIALING: ", this.format(x)); }, format: function(n) { return n.replace(/-/g, '') } }; var numbers = ["234-3535-2342", “1-653-124-8321"]; numbers.map(function(x){ return phone.dial(x); }); // DIALING: 23435352342 // DIALING: 16531248321
  • 42. First Class? var phone = { dial: function(x){ console.log("DIALING: ", this.format(x)); }, format: function(n) { return n.replace(/-/g, '') } }; var numbers = ["234-3535-2342", “1-653-124-8321"]; numbers.map(function(x){ return phone.dial(x); }); // DIALING: 23435352342 // DIALING: 16531248321 numbers.map(phone.dial);
  • 43. First Class? var phone = { dial: function(x){ console.log("DIALING: ", this.format(x)); }, format: function(n) { return n.replace(/-/g, '') } }; var numbers = ["234-3535-2342", “1-653-124-8321"]; numbers.map(function(x){ return phone.dial(x); }); // DIALING: 23435352342 // DIALING: 16531248321 numbers.map(phone.dial); // TypeError: Object #<Object> has no method 'format'
  • 44. First Class? var phone = { dial: function(x){ console.log("DIALING: ", this.format(x)); }, format: function(n) { return n.replace(/-/g, '') } }; var numbers = ["234-3535-2342", “1-653-124-8321"]; numbers.map(function(x){ return phone.dial(x); }); // DIALING: 23435352342 // DIALING: 16531248321 numbers.map(phone.dial.bind(phone)); // DIALING: 23435352342 // DIALING: 16531248321
  • 45. First Class? var phone = { dial: function(x){ console.log("DIALING: ", this.format(x)); }, format: function(n) { return n.replace(/-/g, '') } }; var numbers = ["234-3535-2342", “1-653-124-8321"]; numbers.map(function(x){ return phone.dial(x); }); // DIALING: 23435352342 // DIALING: 16531248321 numbers.map(phone.dial.bind(phone)); // DIALING: 23435352342 // DIALING: 16531248321 BAD
  • 46.
  • 47. //+ render :: [Tag] -> DOM var render = compose($(‘#tag-cloud').html, tagView, addFontSizes) //+ tagCloud :: Params -> Future(DOM) var tagCloud = compose(map(render), httpGet('/tags'))
  • 48. //+ setHtml :: String -> Html -> IO(DOM) var setHtml = curry(function(selector, h) { return IO(function() { return $(selector).html(h); }); }); //+ render :: [Tag] -> IO(DOM) var render = compose(setHtml(‘#tag-cloud'), tagView, addFontSizes) //+ tagCloud :: Params -> Future(IO(DOM)) var tagCloud = compose(map(render), httpGet('/tags'))
  • 49.
  • 50.
  • 51. Pointfree • Removes unnecessary code • High level declarative apps • Encourages generic code • Encourages purity
  • 52. Pointfree • Order of definition matters • Weird interop with imperative community (impure, swiss army fn’s, & ‘this’)
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58. Demos
  • 60. Typeclass promise.then(function(x){ return x + 1 }); // Promise(2) [1].map(function(x) { return x + 1 }); // [2] event_stream.subscribe(function(x) { return x + 1 }) // EventStream(2)
  • 61.
  • 62. Typeclass var Container = function(val) { this.val = val; } Container.prototype.of = function(x) { return new Container(x); } Container.prototype.chain = function(f) { return f(this.val); };
  • 63. Typeclass We can map over them (a -> b) -> M(a) -> M(b)
  • 64. Typeclass We can map over them (a -> b) -> M(a) -> M(b) promise.map(function(x){ return x + 1 }); // Promise(2) [1].map(function(x) { return x + 1 }); // [2] event_stream.map(function(x) { return x + 1 }) // EventStream(2) Just(1).map(function(x) { return x + 1 }) // Just(2) Nothing.map(function(x) { return x + 1 }) // Nothing IO(1).map(function(x) { return x + 1 }) // IO(2)
  • 65. Typeclass We can flatten/un-nest them M(M(a)) -> M(a)
  • 66. Typeclass We can flatten/un-nest them M(M(a)) -> M(a) [['hello']] -> ['hello'] Just(Just(true)) -> Just(true)
  • 67. Typeclass We can apply functions within them M(a -> b) -> M(a) -> M(b)
  • 68. Typeclass We can apply functions within them M(a -> b) -> M(a) -> M(b) var finished = curry(function(click, anim) { alert(“Finished!"); }); EventStream.of(finished).ap(button_clicks).ap(animation_done);
  • 69. Typeclass We can combine them M(a) -> M(a) -> M(a)
  • 70. Typeclass We can combine them M(a) -> M(a) -> M(a) Api.get(‘/unstarred’).concat(Api.get('/starred')) // Future([Item])
  • 71. Typeclass We can compose them M(N(a)) -> MN(a)
  • 72. Typeclass We can compose them M(N(a)) -> MN(a) //+ askQuestion :: IO(Maybe(String)) compose(map(map(storeResponse)), askQuestion) //+ askQuestion :: Compose(IO(Maybe(String))) compose(map(storeResponse), Compose, askQuestion)
  • 73. Typeclass We can commute them M(N(a)) -> N(M(a))
  • 74. Typeclass We can commute them M(N(a)) -> N(M(a)) compose(sequenceA, map(readFile)) // Future([String])
  • 75. Typeclass We can derive lots of this! derive(MyType, [Functor, Applicative, Foldable]) *https://github.com/fantasyland/fantasy-land/pull/66
  • 76.
  • 77.
  • 78. Typeclass //+ validate :: UserAttrs -> Either([Error], UserAttrs) //+ saveUser :: UserAttrs -> Future(User) //+ emailPassword :: User -> Future(Email) //+ saveThenEmail :: UserAttrs -> Future(Email) var saveThenEmail = compose(chain(emailPassword), saveUser) //+ createUser :: UserAttrs -> Either([Error], Future(Email)) var createUser = compose(map(saveThenEmail), validate)
  • 79. Typeclass //+ validate :: UserAttrs -> Either([Error], UserAttrs) //+ saveUser :: UserAttrs -> Future(User) //+ emailPassword :: User -> Future(Email) //+ saveThenEmail :: UserAttrs -> Future(Email) var saveThenEmail = compose(chain(emailPassword), saveUser) //+ createUser :: UserAttrs -> Either([Error], Future(Email)) var createUser = compose(map(saveThenEmail), validate) GOOD
  • 80.
  • 81.
  • 82.
  • 83. GOOD
  • 84.
  • 85. Typeclass //+ lookup :: String -> {String: a} -> a|null var lookup = curry(function(x, obj) { return obj[x]; }) var upperName = compose(toUpperCase, lookup(‘name')) upperName({name: “Tori Amos"}) // “TORI AMOS” upperName({first_name: "Tori", last_name: “Spelling"}) // BOOM!
  • 86. Typeclass //+ safeLookup :: String -> {String: a} -> Maybe(a) var safeLookup = curry(function(x, obj) { return Maybe.fromNullable(obj[x]); }); var upperName = compose(map(toUpperCase), safeLookup(‘name')) upperName({name: “Tori Amos”}) // Just(“TORI AMOS”) upperName({first_name: "Tori", last_name: “Spelling”}) // Nothing
  • 87. Typeclass //+ safeLookup :: String -> {String: a} -> Maybe(a) var safeLookup = curry(function(x, obj) { return Maybe.fromNullable(obj[x]); }); var upperName = compose(map(toUpperCase), safeLookup(‘name')) upperName({name: “Tori Amos”}) // Just(“TORI AMOS”) upperName({first_name: "Tori", last_name: “Spelling”}) // Nothing GOOD
  • 88.
  • 89. GOOD
  • 90.
  • 91. Typeclass //+ readFile :: Future(Maybe(String)) //+ lipogram :: String -> Future(Maybe(String)) var lipogram = compose(map(map(replace(/e/ig))), readFile);
  • 92. Typeclass //+ readFile :: String -> Compose(Future(Maybe(String))) var readFile = compose(Compose, _readFile) //+ lipogram :: String -> Compose(Future(Maybe(String))) var lipogram = compose(map(replace(/e/ig)), readFile);
  • 93. Typeclass var WebApp = ReaderT(StateT(Future))
  • 94. Typeclass Meh var WebApp = ReaderT(StateT(Future))
  • 95.
  • 96. Typeclass do a <- Just 3 b <- Just 1 return a + b Just(3).chain(function(a) { return Just(1).chain(function(b) { return Maybe.of(a + b); }); }; Haskell JavaScript
  • 97. Typeclass do a <- Just 3 b <- Just 1 return a + b Haskell JavaScript liftM2(add, Just(3), Just(1))
  • 98. Typeclass do post_id <- param "id" post <- lift $ findPost post_id return (toJSON post) Haskell (lift . (fmap toJSON) . findPost) =<< param "id" JavaScript chain(compose(lift, map(toJSON), findPost), param(‘id'))
  • 99. Typeclass do post_id <- param "id" post <- lift $ findPost post_id return (toJSON post) Haskell (lift . (fmap toJSON) . findPost) =<< param "id" JavaScript chain(compose(lift, map(toJSON), findPost), param(‘id')) Meh
  • 100.
  • 101. Typeclass do post_id <- param "id" post <- lift $ findPost post_id return (toJSON post) Haskell (lift . (fmap toJSON) . findPost) =<< param "id" JavaScript chain(compose(lift, map(toJSON) findPost), param(‘id'))
  • 102. Typeclass do post_id <- param "id" post <- lift $ findPost post_id return (toJSON post) Haskell (lift . (fmap toJSON) . findPost) =<< param "id" JavaScript chain(compose(WebApp.lift, map(toJSON) findPost), param(‘id'))
  • 103. Typeclass //+ savePhotos :: [Path] -> Future([Photo]) var savePhotos = compose(traverse(uploadPhoto), map(toBlob)) //+ gift :: Future(User) -> Maybe(Future(Card)) var gift = compose(traverse(sendCard, Maybe.of), map(_.get("birthday"))
  • 104. Typeclass //+ savePhotos :: [Path] -> Future([Photo]) var savePhotos = compose(traverse(uploadPhoto), map(toBlob)) //+ gift :: Future(User) -> Maybe(Future(Card)) var gift = compose(traverse(sendCard, Maybe.of), map(_.get("birthday")) BAD
  • 105. Typeclass • Universal interface (across languages) • Generic programs/libraries • Safer programs • Theory backed • Intuition
  • 106. Typeclass • Missing polymorphic “point” • Working ‘blind’ with stacked containers • No syntactic sugar
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112. Demos
  • 113.
  • 114.
  • 115. Shortcut Fusion // g :: forall b. (t -> b -> b) -> b -> b reduce(c, n, build(g)) = g(c, n)
  • 116. Shortcut Fusion //build :: (forall b. (a -> b -> b) -> b -> b) -> [a] var build = function(g){ return g(concat, []); } //+ map :: (a -> b) -> [a] -> [b] var map = curry(function(f, xs){ return build(function(c, n){ return reduce(function(acc, x){ return c(f(x), acc); }, n, xs); }); });
  • 117. Shortcut Fusion var sum = reduce(add, 0); var sqr = function(x) {return x * x } var sumSqs = compose(sum, map(sqr)) // reduce(function(acc, x){ return add(sqr(x), acc) }, 0);
  • 118. Compile while you compose //+ doorman :: [User] -> User var doorman = compose(first, filter(gte(21)), map(_.get('age')));
  • 119.
  • 120. var addTwenty = memoize(function(x) { return x + 20; }) Memoization
  • 121. Memoization var addTwenty = memoize(function(x) { return x + 20; }) addTwenty(10) // 30 addTwenty(10) // 30 (didn't run) addTwenty(11) // 31
  • 122. Memoization var getPosts = memoize(function(id) { return new Future(function(rej, res) { $.getJSON('/posts/'+id, res); }); });
  • 123. Memoization var getPosts = memoize(function(id) { return new Future(function(rej, res) { $.getJSON('/posts/'+id, res); }); }); getPosts(2) // Future getPosts(2) // Future (didn't run) getPosts(3) // Future
  • 124. Memoization var pQuery = $.toIO() pQuery(".troll") // IO(function(){ return $(".troll") }) pQuery.runIO() // [Dom, Dom] pQuery.runIO() // [Dom, Dom, Dom]
  • 126. Parallel code liftA3(fn, A1, A2, A3)
  • 127. Parallel code var longCalc // Int -> Future(Int) var collectResults = curry(function(rslt1, rslt2, rslt3){}) liftA3(collectResults, longCalc(20), longCalc(30), longCalc(10))
  • 128. Parallel code var hasName // Attrs -> Validation liftA3(save, hasName, hasEmail, hasPhone)
  • 129.
  • 130.
  • 131.