SlideShare a Scribd company logo
Functional JavaScript
Alexey Kovalenko
Wix
alexk@wix.com
https://github.com/xxllexx
Functional JavaScript
Imperative & Declarative
Functional JavaScript
1. Imperative and Declarative
What and How
Imperative
Declarative
Functional JavaScript
1. Imperative and Declarative
Imperative
var numbers = [1,2,3,4,5],
total = 0;
for(var i = 0; i < numbers.length; i++) {
total += numbers[i];
}
console.log(total); //=> 15
Functional JavaScript
1. Imperative and Declarative
Declarative
var numbers = [1,2,3,4,5];
var total = numbers.reduce(function(sum, n) {
return sum + n;
});
console.log(total) //=> 15
Functional JavaScript
1. Imperative and Declarative
Declarative Imperative
Java C/C++SQL Go
PHP Python
Haskell
Prolog
Functional JavaScript
1. Imperative and Declarative
JavaScript
Multi Paradigm Language, child of Self and Scheme
From Self:
From Scheme
1) Dynamic dispatch
2) Encapsulation
etc.
1) First class functions
2) Closures
Functional Programming Theory
Functional JavaScript
2. Func. Programming Theory
var str = '';
function join(arr) {
for (var i = 0, l = arr.length; i < l; i++) {
str = str + arr[i];
}
console.log(str);
}
join([0,1,2,3]);//-> ‘0123’
console.log(str === ‘0123');//-> true
Functional JavaScript
2. Func. Programming Theory
function join(arr) {
var str = ‘';
for (var i = 0, l = arr.length; i < l; i++) {
str = str + arr[i];
}
return str;
}
var joinedArr = join([0,1,2,3]);
console.log(joinedArr === ‘0123');//-> true
Functional JavaScript
2. Func. Programming Theory
function join(arr, index, str) {
if (index === arr.length) {
return str
}
return join( arr
, (index || 0) + 1
, (str ? str : '') + arr[index || 0]
);
}
var joinedArr = join([0,1,2,3]);
console.log(joinedArr === ‘0123');//-> true
TCO => ES6
Functional JavaScript
2. Func. Programming Theory
function join(arr, index, str) {
return (index === arr.length)
? str
: join(arr
,(index || 0) + 1
,(str ? str : '') + arr[index || 0]
);
}
var joinedArr = join([0,1,2,3]);
console.log(joinedArr === ‘123');//-> true
Curried functions
Functional JavaScript
3.Curry
var add = function (a, b) {
return a + b;
}
add(1, 2); //-> 3
add(1, 2, 3) //-> 3
add(1); //-> NaN
Functional JavaScript
3.Curry
Developed by Haskell Brooks Curry
curry(f) -> X-> ( Y -> (Z ->N) )
Functional JavaScript
3.Curry
var add = function (a, b) {
return function (b) {
return a + b;
}
}
var result = add(1);
console.log(result);//-> function
console.log(result(100));//-> 101
Functional JavaScript
3.Curry
var fn = curry(function(a, b, c) {
return [a, b, c];
});
fn(‘a', ‘b', ‘c');
fn(‘a', ‘b’)('c');
fn(‘a’)('b', ‘c');
fn(‘a’)(‘b’)('c');
//=> [‘a’, ‘b’, ‘c’]
Functional JavaScript
3.Curry
var filter = curry(function(fn, arr){
return arr.filter(fn);
});
var getOdds = filter(isOdd);
var modulo = curry(function (devisor, devided) {
return devided % devisor;
});
var isOdd = modulo(2);
console.log(filter(isOdd, [1,2,3,4,5,6])) //-> [1, 3, 5];
console.log(getOdds([10,11,12,13,14])) //-> [11, 13];
Functional JavaScript
3.Curry
Lodash: _.curry
Wu.js: wu.autoCurry
Ramdajs: R.curry
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
Composition (Category Theory)
Functional JavaScript
4. Composition
Composition
A B
C
g
f
f ∘ g
f ∘ g = f(g(x))
Functional JavaScript
4. Composition
var compose = function(f, g) {
return function(x) {
return f(g(x));
};
};
Simple Javascript composition function
var sine = function(x) { return Math.sin(x) };
var cube = function(x) { return x * x * x };
var sineOfCube = compose(sine, cube);
sineOfCube(10) === sine(cube(10)); //-> true
Functional JavaScript
4. Composition
Composition & Curry
var limit = curry(function(num, data){
return data.slice(0, num);
});
var _map = curry(function(fn, arr){
return arr.map(fn);
});
var getProp = curry(function(prop, obj){
return obj[prop];
});
Functional JavaScript
4. Composition
Composition & Curry
var users = [
{name: 'Ivan', age: 18},
{name: 'Katya', age: 23},
{name: 'Victor', age: 18},
{name: 'Nata', age: 14},
{name: 'Alex', age: 18},
{name: 'Sveta', age: 34}
];
var usersList = compose(_map(getProp('name')), limit(4));
usersList(users);//-> ["Ivan", "Katya", "Victor", "Nata"]
users{6}users{4}users{4}:name
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
Functors
Functional JavaScript
5. Functor
function addOne(a) {
return a + 1;
};
addOne(5);
//-> 6
addOne([5]);
//-> 51
Functional JavaScript
5. Functor
fmap :: (a -> b) -> f a -> f b
class (typeclass) Functor f where
Functional JavaScript
5. Functor
fmap :: (a -> b) -> [a] -> [b]
JS map -> Functor Lift
[0, 1, 2, 3].map(addOne);
//-> [1, 2, 3, 4];
[addOne(0), addOne(1), addOne(2) ...]
//-> [1, 2, 3, 4];
Functional JavaScript
5. Functor
var fmap = curry(function(f, obj) {
return obj.fmap(f);
});
Functional JavaScript
5. Functor
var AnyFunctor = function(val){
if(!(this instanceof AnyFunctor))
return new AnyFunctor(val);
this.val = val;
};
AnyFunctor.prototype.fmap = function(fn){
return AnyFunctor(fn(this.val));
}
fmap(addOne, AnyFunctor(2)); //-> AnyFunctor(3)
Functional JavaScript
5. Functor
AnyFunctor.prototype.fmap = function(fn){
return AnyFunctor(this.val.map(fn));
}
fmap(addOne, AnyFunctor([0, 2, 3, 4]));
//-> AnyFunctor([1, 2, 3, 4]);
Functional JavaScript
5. Functor
Functor Maybe
Functional JavaScript
5. Functor
var Maybe = function(val) {
if (!(this instanceof Maybe)) {
return new Maybe(val);
}
this.val = val;
};
Maybe.prototype.fmap = function(f){
return this.val == null
? Maybe(null)
: Maybe(f(this.val));
};
Functional JavaScript
5. Functor
var concat = curry(function(foo, bar){ return foo + bar; });
var pluck = curry(function(prop, obj){ return obj[prop]; });
var match = curry(function (reg, str) { return str.match(reg); });
var showLength = compose(concat('The length is: '), pluck('length'));
var getWords = compose(Maybe, match(/w+/g));
var program = compose(fmap(showLength), getWords);
var result = program('Hello world'); //-> Maybe {val: "The length is: 2"}
Functional JavaScript
5. Functor
var match = curry(function (reg, str) {
return str.match(reg);
});
getWords('Hello World')
//-> Maybe {val: ['Hello', 'World']}
getWords()
//-> Maybe {val: null}
var getWords = compose(fmap(match(/w+/g)), Maybe);
compose(
fmap(match(/w+/g)),
Maybe
);
String | null
Maybe {
val: String | null,
fmap: fn
}
Maybe.fmap(match(reg))
Maybe {
val: match(reg)(String)
}
Maybe {
val: null
}
String
null
Ramda
“a practical functional library for Javascript programmers.”
Functional JavaScript
6. Ramda
Underscore / Lodash
var map = R.map(function(n) { return n * 2; });
map([1, 2, 3]);
_.map([1, 2, 3], function(n) { return n * 2; });
Ramda
R.map(function(n) { return n * 2; }, [1, 2, 3]);
data function
datafunction
Functional JavaScript
6. Ramda
Underscore / Lodash
var users = [
{ 'user': 'Alex', 'age': 36 },
{ 'user': 'Ivan', 'age': 40 },
{ 'user': 'Ted', 'age': 1 }
];
var youngest = _.chain(users)
.sortBy('age')
.map(function(chr) {
return chr.user + ' is ' + chr.age;
})
.first()
.value();
var youngest = _.first(_.map(_.sortBy(users, 'age'), function(ch){
return chr.user + ' is ' + chr.age;
}));
Functional JavaScript
6. Ramda
Ramda
var sorted = R.sortBy(R.prop('age'));
var transformed = R.map(mapFn);
var getOne = R.take(1);
var program = R.compose(transformed, getOne, sorted);
var youngest = program(users);
var mapFn = function(chr){
return chr.user + ' is ' + chr.age;
};
console.log(sorted(users));
console.log(transformed(users));
console.log(getOne(users));
console.log(youngest);
Functional JavaScript
6. Ramda
Ramda
var capitalize = R.compose(
R.map(R.toUpper),
R.map(R.prop('textContent')),
Maybe,
R.bind(document.getElementById, document)
);
// String -> DOMElement
// Object -> Maybe Object
// Maybe Object -> Maybe String
// Maybe String -> Maybe String
<div id="elementId">Hello World</div>
capitalize('elementId');
//-> Maybe {val: "HELLO WORLD", map: function}
capitalize('elementId2');
//-> Maybe {val: null, map: function}
Links
Taking Things Out of Context: Functors in JavaScript:
http://mattfield.github.io/javascript/2013/07/28/taking-things-out-of-context-functors-in-javascript/
Functors, Applicatives, And Monads In Pictures:
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
Hey Underscore, You're Doing It Wrong!:
https://www.youtube.com/watch?v=m3svKOdZijA
Functional programming patterns for the non-mathematician (cut):
https://www.youtube.com/watch?v=AvgwKjTPMmM
https://github.com/DrBoolean/patterns_talk
Functional JavaScript, Part 4: Function Currying:
http://tech.pro/tutorial/2011/functional-javascript-part-4-function-currying
Introducing Ramda:
http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda/
Thank You!

More Related Content

"Немного о функциональном программирование в JavaScript" Алексей Коваленко

  • 4. Functional JavaScript 1. Imperative and Declarative What and How Imperative Declarative
  • 5. Functional JavaScript 1. Imperative and Declarative Imperative var numbers = [1,2,3,4,5], total = 0; for(var i = 0; i < numbers.length; i++) { total += numbers[i]; } console.log(total); //=> 15
  • 6. Functional JavaScript 1. Imperative and Declarative Declarative var numbers = [1,2,3,4,5]; var total = numbers.reduce(function(sum, n) { return sum + n; }); console.log(total) //=> 15
  • 7. Functional JavaScript 1. Imperative and Declarative Declarative Imperative Java C/C++SQL Go PHP Python Haskell Prolog
  • 8. Functional JavaScript 1. Imperative and Declarative JavaScript Multi Paradigm Language, child of Self and Scheme From Self: From Scheme 1) Dynamic dispatch 2) Encapsulation etc. 1) First class functions 2) Closures
  • 10. Functional JavaScript 2. Func. Programming Theory var str = ''; function join(arr) { for (var i = 0, l = arr.length; i < l; i++) { str = str + arr[i]; } console.log(str); } join([0,1,2,3]);//-> ‘0123’ console.log(str === ‘0123');//-> true
  • 11. Functional JavaScript 2. Func. Programming Theory function join(arr) { var str = ‘'; for (var i = 0, l = arr.length; i < l; i++) { str = str + arr[i]; } return str; } var joinedArr = join([0,1,2,3]); console.log(joinedArr === ‘0123');//-> true
  • 12. Functional JavaScript 2. Func. Programming Theory function join(arr, index, str) { if (index === arr.length) { return str } return join( arr , (index || 0) + 1 , (str ? str : '') + arr[index || 0] ); } var joinedArr = join([0,1,2,3]); console.log(joinedArr === ‘0123');//-> true TCO => ES6
  • 13. Functional JavaScript 2. Func. Programming Theory function join(arr, index, str) { return (index === arr.length) ? str : join(arr ,(index || 0) + 1 ,(str ? str : '') + arr[index || 0] ); } var joinedArr = join([0,1,2,3]); console.log(joinedArr === ‘123');//-> true
  • 15. Functional JavaScript 3.Curry var add = function (a, b) { return a + b; } add(1, 2); //-> 3 add(1, 2, 3) //-> 3 add(1); //-> NaN
  • 16. Functional JavaScript 3.Curry Developed by Haskell Brooks Curry curry(f) -> X-> ( Y -> (Z ->N) )
  • 17. Functional JavaScript 3.Curry var add = function (a, b) { return function (b) { return a + b; } } var result = add(1); console.log(result);//-> function console.log(result(100));//-> 101
  • 18. Functional JavaScript 3.Curry var fn = curry(function(a, b, c) { return [a, b, c]; }); fn(‘a', ‘b', ‘c'); fn(‘a', ‘b’)('c'); fn(‘a’)('b', ‘c'); fn(‘a’)(‘b’)('c'); //=> [‘a’, ‘b’, ‘c’]
  • 19. Functional JavaScript 3.Curry var filter = curry(function(fn, arr){ return arr.filter(fn); }); var getOdds = filter(isOdd); var modulo = curry(function (devisor, devided) { return devided % devisor; }); var isOdd = modulo(2); console.log(filter(isOdd, [1,2,3,4,5,6])) //-> [1, 3, 5]; console.log(getOdds([10,11,12,13,14])) //-> [11, 13];
  • 23. Functional JavaScript 4. Composition Composition A B C g f f ∘ g f ∘ g = f(g(x))
  • 24. Functional JavaScript 4. Composition var compose = function(f, g) { return function(x) { return f(g(x)); }; }; Simple Javascript composition function var sine = function(x) { return Math.sin(x) }; var cube = function(x) { return x * x * x }; var sineOfCube = compose(sine, cube); sineOfCube(10) === sine(cube(10)); //-> true
  • 25. Functional JavaScript 4. Composition Composition & Curry var limit = curry(function(num, data){ return data.slice(0, num); }); var _map = curry(function(fn, arr){ return arr.map(fn); }); var getProp = curry(function(prop, obj){ return obj[prop]; });
  • 26. Functional JavaScript 4. Composition Composition & Curry var users = [ {name: 'Ivan', age: 18}, {name: 'Katya', age: 23}, {name: 'Victor', age: 18}, {name: 'Nata', age: 14}, {name: 'Alex', age: 18}, {name: 'Sveta', age: 34} ]; var usersList = compose(_map(getProp('name')), limit(4)); usersList(users);//-> ["Ivan", "Katya", "Victor", "Nata"] users{6}users{4}users{4}:name
  • 29. Functional JavaScript 5. Functor function addOne(a) { return a + 1; }; addOne(5); //-> 6 addOne([5]); //-> 51
  • 30. Functional JavaScript 5. Functor fmap :: (a -> b) -> f a -> f b class (typeclass) Functor f where
  • 31. Functional JavaScript 5. Functor fmap :: (a -> b) -> [a] -> [b] JS map -> Functor Lift [0, 1, 2, 3].map(addOne); //-> [1, 2, 3, 4]; [addOne(0), addOne(1), addOne(2) ...] //-> [1, 2, 3, 4];
  • 32. Functional JavaScript 5. Functor var fmap = curry(function(f, obj) { return obj.fmap(f); });
  • 33. Functional JavaScript 5. Functor var AnyFunctor = function(val){ if(!(this instanceof AnyFunctor)) return new AnyFunctor(val); this.val = val; }; AnyFunctor.prototype.fmap = function(fn){ return AnyFunctor(fn(this.val)); } fmap(addOne, AnyFunctor(2)); //-> AnyFunctor(3)
  • 34. Functional JavaScript 5. Functor AnyFunctor.prototype.fmap = function(fn){ return AnyFunctor(this.val.map(fn)); } fmap(addOne, AnyFunctor([0, 2, 3, 4])); //-> AnyFunctor([1, 2, 3, 4]);
  • 36. Functional JavaScript 5. Functor var Maybe = function(val) { if (!(this instanceof Maybe)) { return new Maybe(val); } this.val = val; }; Maybe.prototype.fmap = function(f){ return this.val == null ? Maybe(null) : Maybe(f(this.val)); };
  • 37. Functional JavaScript 5. Functor var concat = curry(function(foo, bar){ return foo + bar; }); var pluck = curry(function(prop, obj){ return obj[prop]; }); var match = curry(function (reg, str) { return str.match(reg); }); var showLength = compose(concat('The length is: '), pluck('length')); var getWords = compose(Maybe, match(/w+/g)); var program = compose(fmap(showLength), getWords); var result = program('Hello world'); //-> Maybe {val: "The length is: 2"}
  • 38. Functional JavaScript 5. Functor var match = curry(function (reg, str) { return str.match(reg); }); getWords('Hello World') //-> Maybe {val: ['Hello', 'World']} getWords() //-> Maybe {val: null} var getWords = compose(fmap(match(/w+/g)), Maybe); compose( fmap(match(/w+/g)), Maybe ); String | null Maybe { val: String | null, fmap: fn } Maybe.fmap(match(reg)) Maybe { val: match(reg)(String) } Maybe { val: null } String null
  • 39. Ramda “a practical functional library for Javascript programmers.”
  • 40. Functional JavaScript 6. Ramda Underscore / Lodash var map = R.map(function(n) { return n * 2; }); map([1, 2, 3]); _.map([1, 2, 3], function(n) { return n * 2; }); Ramda R.map(function(n) { return n * 2; }, [1, 2, 3]); data function datafunction
  • 41. Functional JavaScript 6. Ramda Underscore / Lodash var users = [ { 'user': 'Alex', 'age': 36 }, { 'user': 'Ivan', 'age': 40 }, { 'user': 'Ted', 'age': 1 } ]; var youngest = _.chain(users) .sortBy('age') .map(function(chr) { return chr.user + ' is ' + chr.age; }) .first() .value(); var youngest = _.first(_.map(_.sortBy(users, 'age'), function(ch){ return chr.user + ' is ' + chr.age; }));
  • 42. Functional JavaScript 6. Ramda Ramda var sorted = R.sortBy(R.prop('age')); var transformed = R.map(mapFn); var getOne = R.take(1); var program = R.compose(transformed, getOne, sorted); var youngest = program(users); var mapFn = function(chr){ return chr.user + ' is ' + chr.age; }; console.log(sorted(users)); console.log(transformed(users)); console.log(getOne(users)); console.log(youngest);
  • 43. Functional JavaScript 6. Ramda Ramda var capitalize = R.compose( R.map(R.toUpper), R.map(R.prop('textContent')), Maybe, R.bind(document.getElementById, document) ); // String -> DOMElement // Object -> Maybe Object // Maybe Object -> Maybe String // Maybe String -> Maybe String <div id="elementId">Hello World</div> capitalize('elementId'); //-> Maybe {val: "HELLO WORLD", map: function} capitalize('elementId2'); //-> Maybe {val: null, map: function}
  • 44. Links Taking Things Out of Context: Functors in JavaScript: http://mattfield.github.io/javascript/2013/07/28/taking-things-out-of-context-functors-in-javascript/ Functors, Applicatives, And Monads In Pictures: http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html Hey Underscore, You're Doing It Wrong!: https://www.youtube.com/watch?v=m3svKOdZijA Functional programming patterns for the non-mathematician (cut): https://www.youtube.com/watch?v=AvgwKjTPMmM https://github.com/DrBoolean/patterns_talk Functional JavaScript, Part 4: Function Currying: http://tech.pro/tutorial/2011/functional-javascript-part-4-function-currying Introducing Ramda: http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda/