layout | style |
---|---|
default |
.slide.center h2 {
margin: 0px 0 30px 0;
}
.slide.center .copy {
margin-top: 40px;
font-size: 12px;
}
|
{% if site.presentation.nda %}
{% endif %}{{ site.author.name }},
{{ site.author.position }}
{:.section}
- ...1950 - 1960г
- ...LISP, Haskell
- ...javascript ?
{:.with-big-quote}
Что такое ФП?
{:.with-big-quote}
Это набор идей, а не чёткие инструкции и действия
{:.section}
- Функции должны быть объектами высшего порядка
var calculateTotalPrice = data => {
// ...
};
fs.readFile('./offers.csv', 'utf8', calculateTotalPrice);
- Функции должны быть объектами высшего порядка
- Функция не должна изменять внешнее состояние
var someGlobalFlag = true;
var swapState = data => {
if (data.needSwapState) {
someGlobalFlag = !someGlobalFlag;
}
};
var someGlobalFlag = true;
var swapState = (data, flag) => {
if (data.needSwapState) {
return flag ? true : false;
}
};
var newGlobalFlag = swapState(data, someGlobalFlag);
- Функции должны быть объектами высшего порядка
- Функция не должна изменять внешнее состояние
- Функция не должна изменять переданные ей аргументы
var toUpperCaseAll = (list) => {
for (let i = 0; i < list.length; i++) {
list[i] = list[i].toUpperCase();
}
return list;
};
toUpperCaseAll(['mike', 'leo', 'raf', 'don']);
// ['MIKE', 'LEO', 'RAF', 'DON']
var toUpperCaseAll = (list) => {
var result = [];
for (let i = 0; i < list.length; i++) {
result[i] = list[i].toUpperCase();
}
return result;
};
toUpperCaseAll(['mike', 'leo', 'raf', 'don']);
// ['MIKE', 'LEO', 'RAF', 'DON']
- Функции должны быть объектами высшего порядка
- Функция не должна изменять внешнее состояние
- Функция не должна изменять переданные ей аргументы
- Результат функции зависит только от переданных ей аргументов
var add = (a, b) => a + b;
add(2, 5) // 5
add(2, 5) // 5
add(2, 5) // 5
{:.with-big-quote}
Чистые функции
{:.section}
- Расчётов
- ...Заменяем переменные
- ...Заменяем циклы и управляющие структуры
- ...Описываем изменение состояния программы
a + b
var add = (a, b) => a + b;
add(2, 5);
var five = 5;
var five = () => 5;
var transformList = (callback, list) => {
var result = [];
for (let value of list) {
let newValue = callback(value);
result.push(newValue);
}
return result;
}
function transformList(callback, [x, ...list]) {
if (!x) return [];
return [callback(x), . . . transformList(callback, list)];
}
{:.section}
- Инструменты
- ...Замыкания
- ...Каррирование
- ...Композиция
var add = function (x) {
return function (y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
var add3 = (a, b, c) => a + b + c;
var add3Curryed = curry(add3);
add3Curryed(1, 2, 3); // 6
add3Curryed(1)(2, 3); // 6
add3Curryed(1, 2)(3); // 6
add3Curryed(1)(2)(3); // 6
curry = func => {
var arity = func.length;
return function f1(. . . args) {
if (args.length >= arity) {
return func.apply(null, args);
} else{
return function f2(. . . nargs) {
return f1.apply(null, args.concat(nargs));
};
}
};
};
var capitalize = str => str.charAt(0).toUpperCase() + str.slice(1);
var trim = str => str.trim();
var formatStr = compose(capitalize, trim);
var split = curry((separator, str) => str.split(separator));
var join = curry((separator, list) => list.join(separator));
var map = curry((func, list) => list.map(func));
var toLowerCase = str => str.toLowerCase();
var toSlug = compose(
encodeURIComponent,
joinString('-'),
map(stringToLowerCase),
splitString(' ')
);
var compose = (. . . funcs) =>
(value) => funcs.reverse().reduce((v,fn) => fn(v), value);
- ...Предсказуемое поведение
- ...Чистые функции легче рафакторить
- ...Чистые функции проще отлаживать и тестировать
- ...Чистые функции легко поддаются оптимизации
- ...Можем откладывать и параллелить вычисления
{:.section}
- Запись логов
- Запись в localStorage
- Обращение к DOM элементам
- Отправка запросов на сервер
- и тд.
- ramda.js
- ramda-fantasy.js
var getRows = pluck('rows');
var getNames = pluck('name');
var renderUsersTable = Engine.render('users-table');
var getUsersFromDb = compose(getRows, User.findAll);
var cleanUpData = compose(capitalise, getNames);
var makePage = compose(renderUsersTable, map(cleanUpData), getUsersFromDb);
makePage( {limit: 20} );
{:.section}
var Container = function(x) {
this.__value = x;
};
Container.of = x => new Container(x);
Container.prototype.map = func => {
return Container.of(func(this.__value));
};
Container.of(2).map(function(two){ return two + 2 });
// Container(4)
{:.section}
var getUsersFromDb = compose(getRows, User.findAll);
var getUsersFromDb = compose(getRows, Maybe.of, User.findAll);
var getUsersFromDb = compose(map(getRows), Maybe.of, User.findAll);
getUsersFromDb() // Maybe([{name: 'leo', name: 'don']);
getUsersFromDb() // Maybe(null);
var Maybe = function(x) {
this.__value = x;
}
Maybe.of = function(x) {
return new Maybe(x);
}
Maybe.prototype.isNothing = function() {
return (this.__value === null || this.__value === undefined);
}
Maybe.prototype.map = function(f) {
return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value));
}
{:.section}
var renderUsersTable = Engine.render('users-table');
var makePage = compose(
map(renderUsersTable),
map(cleanUpData),
getUsersFromDb
);
var errorMessage = 'sorry there is no users';
var errorContainer = Either.Left(errorMessage);
var getUsers = cond([
[isArrayLike, Either.Right],
[T, always(errorContainer)]
]);
var getUsersFromDb = compose(map(getRows), getUsers, User.findAll);
var renderUsersTable = Engine.render('users-table');
var renderErrorMessage = Engine.render('error-message');
var render = Either.either(renderErrorMessage, renderUsersTable);
var makePage = compose(render, getUsersFromDb);
{:.section}
var getUsersFromDb = compose(getRows, User.findAll);
var findAll = params =>
Future((reject, resolve) =>
User.findAll(params)
.then(resolve)
.catch(reject));
var getUsersFromDb = compose(map(getRows), findAll);
var makePage = compose(map(cleanUpData), getUsersFromDb);
var page = makePage({limit: 20});
page.fork(renderErrorMessage, renderUsersTable);
{:.section}
var getRows = pluck('rows');
var getNames = pluck('name');
var cleanUpData = compose(capitalise, getNames);
var renderUsersTable = Engine.render('users-table');
var renderErrorMessage = Engine.render('error-message');
var render = Either.either(renderErrorMessage, renderUsersTable);
var render = . . .
var errorMessage = 'sorry there is no users';
var errorContainer = Either.Left(errorMessage);
var getUsers = cond([
[isArrayLike, Either.Right],
[T, always(errorContainer)]
]);
var findAll = params =>
Future((reject, resolve) =>
User.findAll(params).then(resolve).catch(reject));
var getUsersFromDb = compose(flatMap(getRows), map(getUsers), findAll);
var render = . . .
var getUsersFromDb = . . .
var makePage = compose(map(render), flatMap(cleanUpData), getUsersFromDb);
var page = makePage({limit: 20});
page.fork(logError, insertToDOM);
Homer Simpson. ©1999 20TH CENTURY FOX FILM CORP. {:.copy}
- ...Легко рефакторить
- ...Легко тестировать
- ...Легко оптимизировать
- ...За функциональным программированием будущее
- ...Есть порог вхождения
- ...Может быть слишком многословным
- ...Может быть менее производительным
- https://github.com/MostlyAdequate/mostly-adequate-guide-ru
- http://ramdajs.com/docs/
- https://github.com/ramda/ramda-fantasy
- https://github.com/fantasyland/fantasy-land
{{ site.author.name }}
{{ site.author.position }}
<div class="contacts">
<p class="contacts-left mail">[email protected]</p>
<p class="contacts-left contacts-top twitter">@tka4enko1503</p>
</div>