SlideShare a Scribd company logo
Fact, Fiction, and FP
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
Fact, Fiction, and FP
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 });
Fact, Fiction, and FP
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?"))
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
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
Fact, Fiction, and FP
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
Fact, Fiction, and FP
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
Fact, Fiction, and FP
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
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
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
Fact, Fiction, and FP
//+ 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'))
Fact, Fiction, and FP
Fact, Fiction, and FP
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’)
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
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)
Fact, Fiction, and FP
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
Fact, Fiction, and FP
Fact, Fiction, and FP
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
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
GOOD
Fact, Fiction, and FP
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
Fact, Fiction, and FP
GOOD
Fact, Fiction, and FP
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))
Fact, Fiction, and FP
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
Fact, Fiction, and FP
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
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
Demos
Fact, Fiction, and FP
Fact, Fiction, and FP
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')));
Fact, Fiction, and FP
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)
Fact, Fiction, and FP
Fact, Fiction, and FP
Fact, Fiction, and FP
THANKS! 
@drboolean

More Related Content

PPTX
PPTX
Ricky Bobby's World
PDF
Elm: give it a try
PDF
Cycle.js: Functional and Reactive
PPTX
Super Advanced Python –act1
KEY
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
PDF
Functional programming using underscorejs
PDF
Ricky Bobby's World
Elm: give it a try
Cycle.js: Functional and Reactive
Super Advanced Python –act1
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Functional programming using underscorejs

What's hot (20)

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

Viewers also liked (8)

PPTX
Oh Composable World!
PPTX
Millionways
KEY
Functional Reactive Programming in Javascript
KEY
Functional js class
PPT
Liftin every day
PPT
Js for learning
PPS
Underscore
PPT
Functional Patterns for the non-mathematician
Oh Composable World!
Millionways
Functional Reactive Programming in Javascript
Functional js class
Liftin every day
Js for learning
Underscore
Functional Patterns for the non-mathematician
Ad

Similar to Fact, Fiction, and FP (20)

PDF
Say It With Javascript
PPTX
Academy PRO: ES2015
PDF
Javascript
PDF
JSDC 2014 - functional java script, why or why not
PDF
Intro to Advanced JavaScript
PDF
ES6: The future is now
PPTX
Functional programming in javascript
PDF
Functional JS for everyone - 4Developers
PPTX
What’s new in ECMAScript 6.0
PPTX
Awesomeness of JavaScript…almost
PDF
JavaScript Primer
PDF
mobl - model-driven engineering lecture
PDF
The Future of JavaScript (Ajax Exp '07)
PDF
ECMAScript2015
PDF
Introduction to ECMAScript 2015
PPT
Wakanday JS201 Best Practices
PDF
Workshop 10: ECMAScript 6
KEY
Object-Oriented JavaScript
KEY
Object-Oriented Javascript
PDF
The many facets of code reuse in JavaScript
Say It With Javascript
Academy PRO: ES2015
Javascript
JSDC 2014 - functional java script, why or why not
Intro to Advanced JavaScript
ES6: The future is now
Functional programming in javascript
Functional JS for everyone - 4Developers
What’s new in ECMAScript 6.0
Awesomeness of JavaScript…almost
JavaScript Primer
mobl - model-driven engineering lecture
The Future of JavaScript (Ajax Exp '07)
ECMAScript2015
Introduction to ECMAScript 2015
Wakanday JS201 Best Practices
Workshop 10: ECMAScript 6
Object-Oriented JavaScript
Object-Oriented Javascript
The many facets of code reuse in JavaScript

Recently uploaded (20)

PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Electronic commerce courselecture one. Pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
NewMind AI Monthly Chronicles - July 2025
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPT
Teaching material agriculture food technology
PDF
Modernizing your data center with Dell and AMD
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Machine learning based COVID-19 study performance prediction
PDF
KodekX | Application Modernization Development
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
cuic standard and advanced reporting.pdf
PPTX
Cloud computing and distributed systems.
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Electronic commerce courselecture one. Pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
NewMind AI Monthly Chronicles - July 2025
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Building Integrated photovoltaic BIPV_UPV.pdf
Teaching material agriculture food technology
Modernizing your data center with Dell and AMD
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Unlocking AI with Model Context Protocol (MCP)
Machine learning based COVID-19 study performance prediction
KodekX | Application Modernization Development
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
The AUB Centre for AI in Media Proposal.docx
cuic standard and advanced reporting.pdf
Cloud computing and distributed systems.
Network Security Unit 5.pdf for BCA BBA.
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Encapsulation_ Review paper, used for researhc scholars

Fact, Fiction, and FP

  • 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
  • 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 });
  • 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?"))
  • 17. Pointfree httpGet('/post/2', function(json, err){ renderPost(json, err); });
  • 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
  • 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
  • 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
  • 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
  • 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'))
  • 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’)
  • 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)
  • 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
  • 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
  • 83. GOOD
  • 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
  • 89. GOOD
  • 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))
  • 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
  • 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
  • 112. Demos
  • 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')));
  • 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)