SlideShare uma empresa Scribd logo
1 de 132
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

Mais conteúdo relacionado

Mais procurados

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 StripeStripe
 
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
 
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: HackVic 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
 
Coscup2021-rust-toturial
Coscup2021-rust-toturialCoscup2021-rust-toturial
Coscup2021-rust-toturialWayne Tsai
 
Malli: inside data-driven schemas
Malli: inside data-driven schemasMalli: inside data-driven schemas
Malli: inside data-driven schemasMetosin Oy
 
MiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptMiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptCaridy Patino
 
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 usageWayne 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 Fieldfabulouspsychop39
 
Зависимые типы в 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 malliMetosin Oy
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With ClojureMetosin Oy
 
Test Driven Cocos2d
Test Driven Cocos2dTest Driven Cocos2d
Test Driven Cocos2dEric Smith
 

Mais procurados (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
 

Destaque

Functional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptFunctional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptBrian Lonsdorf
 
Functional Patterns for the non-mathematician
Functional Patterns for the non-mathematicianFunctional Patterns for the non-mathematician
Functional Patterns for the non-mathematicianBrian Lonsdorf
 

Destaque (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
 

Semelhante a 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 JavaScriptVisual 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 HorizonAlex Payne
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScriptLuis Atencio
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry 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 2015Michiel 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 Librariesjeresig
 
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 JavaScriptGuy Royse
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyDavid 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 HTML5Doris 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 practicesAnkit Rastogi
 
Intro to Javascript
Intro to JavascriptIntro to Javascript
Intro to JavascriptAnjan Banda
 

Semelhante a 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
 

Último

Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbuapidays
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusZilliz
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 

Último (20)

Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 

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.