SlideShare ist ein Scribd-Unternehmen logo
1 von 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

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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
 

Andere mochten auch

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
 

Andere mochten auch (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
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Kürzlich hochgeladen

GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
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
 
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
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 

Kürzlich hochgeladen (20)

GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
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
 
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
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

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.