SlideShare a Scribd company logo
1 of 47
Download to read offline
C++ User Group, Новосибирск 
Функционально-декларативный 
дизайн на С++ 
Александр Гранин 
graninas@gmail.com
О себе 
● C++ → Haskell 
● Рассказывал на DevDay@2GIS о Haskell 
● Рассказывал на TechTalks@NSU о ФП 
● Статьи на Хабре о дизайне в ФП 
● Работаю в “Лаборатории Касперского”
struct Presentation 
{ 
Описание задачи 
Функциональная комбинаторика 
Продвинутый дизайн 
Тестирование 
Проблемы и особенности 
};
О задаче 
● Игра “Амбер” (По мотивам “Хроник Амбера” Роджера Желязны) 
● C++11 (Qt C++ 5.2.1, gcc 4.8.2) 
● Функционально-декларативный дизайн 
● Максимум смысла, минимум кода 
● https://github.com/graninas/Amber
Ограничения 
● Нет классов, только struct (POD) 
● Списки инициализации! 
● Нет циклов for(;;), есть for_each() 
● Всяческие eDSLs 
● Иммутабельность 
● Лямбды, функции, замыкания
Структура Амбера 
Полюс 
Амбера Средние миры 
Полюс 
Хаоса 
Амбер 
Бергма 
Кашфа 
Авалон 
Земля 
Дворы 
Хаоса
Координаты тени, игрока 
Полюс 
Амбера 
Амбер 
G(90) W(10) A(100) S(70) 
Бергма 
Кашфа 
Авалон 
G(30) W(70) A(80) S(90) 
Амбер: 
90 Земля (G) 
10 Вода (W) 
100 Воздух (A) 
70 Небо (S) 
100 Флора 
100 Фауна 
0 Расстояние до Амбера 
100 Расстояние до Хаоса
Коородинаты тени, игрока 
namespace Element { 
enum ElementType { 
Air, 
Sky, 
Water, 
Ground 
}; 
} 
Амбер 
Бергма 
Кашфа 
Авалон 
Игрок: 
90 Земля 
10 Вода 
100 Воздух 
70 Небо 
typedef std::map<Element::ElementType, int> ShadowStructure;
Декларативное задание координат 
ShadowStructure::value_type Air(int air) { 
return ShadowStructure::value_type(Element::Air, air); 
} 
ShadowStructure amberShadowStructure() { 
return { 
{ Element::Ground, 90 } 
, { Element::Water, 10 } 
, Air(100) 
, Sky(70) 
}; 
}
Определение тени 
typedef std::function<ShadowStructure(ShadowStructure, 
Direction::DirectionType)> 
ShadowVariator; 
struct Shadow { 
ShadowName name; 
ShadowVariator variator; 
ShadowStructure structure; 
double influence; 
};
ShadowVariator координат игрока 
typedef std::function<ShadowStructure(ShadowStructure, 
Direction::DirectionType)> 
ShadowVariator; 
const ShadowVariator identityVariator = 
[](const ShadowStructure& structure, 
Direction::DirectionType) 
{ 
return structure; 
}; 
N 
Ground 
S 
Water 
E 
Sky 
W 
Air
ShadowVariator координат игрока 
const ShadowVariator bergmaVariator = 
[](const ShadowStructure& structure, 
Direction::DirectionType dir) -> ShadowStructure { 
switch (dir) { 
case Direction::North: 
return changeElements({ element::Water(-2) 
, element::Ground(2) } 
, structure); 
// and so on for the different directions... 
} 
};
Игровой процесс 
Input Output 
Amber 1 
AmberTask 
Evaluator 
AAmmbbeerTrTaasksk AmberTask Amber 2
AmberTask - задачи на лямбдах 
typedef std::function<Amber (const Amber&)> AmberTask; 
const AmberTask goNorth = [](const Amber& amber) { 
const ShadowVariator variator = // somehow get variator 
Amber newAmber = amber; 
newAmber.playerPos = variator(amber.playerPos, Direction::North); 
return newAmber; 
};
Список задач 
typedef std::function<Amber (const Amber&)> AmberTask; 
typedef std::list<AmberTask> AmberTaskList; 
Amber goNorth(const Amber& amber) { 
AmberTaskList tasks = { 
goNorth, 
inflateShadowStorms, 
tickWorldTime 
}; 
return evaluate(amber, tasks); 
}
Выполнение списка задач 
typedef std::function<Amber (const Amber&)> AmberTask; 
typedef std::list<AmberTask> AmberTaskList; 
Amber evaluate(const Amber& amber, const AmberTaskList& tasks) { 
Amber currentAmber = amber; 
std::for_each(tasks.begin(), tasks.end(), 
[&currentAmber](const AmberTask& task) { 
currentAmber = task(currentAmber); 
}); 
return currentAmber; 
}
Boilerplate 
const AmberTask goNorth = [](const Amber& amber) { 
// Bla-bla with Direction::North 
}; 
const AmberTask goSouth = [](const Amber& amber) { 
// The same Bla-bla with Direction::South 
}; 
// And so on...
Конструирование лямбд 
AmberTask goDirection(Direction::DirectionType dir) { 
return [dir](const Amber& amber) { 
// Bla-bla with dir 
}; 
} 
AmberTaskList tasks = { 
goDirection(Direction::North), 
inflateShadowStorms, 
tickWorldTime 
};
Небезопасный код 
const AmberTask inflateShadowStorms = [](const Amber& amber) 
{ 
throw std::runtime_error("Shit happened! :)"); 
};
Данные + результат onSuccess 
Task 
Amber 1 
Result 1 
Amber 2 
if (Result 1 
== Success) 
+ 
- 
onFail Task safeEvalTask 
Result 2 
safeEvalTask
Комбинаторный eDSL 
const AmberTask tickOneAmberHour = [](const Amber& amber) { 
auto action1Res = anyway (inflateShadowStorms, wrap(amber)); 
auto action2Res = onSuccess (affectShadowStorms, action1Res); 
auto action3Res = onFail (shadowStabilization, action2Res); 
auto action4Res = anyway (tickWorldTime, action3Res); 
return action4Res.amber; 
}; 
AmberTask goNorthTask = [](const Amber& amber) { 
auto action1Res = anyway (goNorth, wrap(amber)); 
auto action2Res = anyway (tickOneAmberHour, action1Res); 
return action2Res.amber; 
};
Комбинаторы 
struct Artifact { 
Amber amber; 
bool success; 
}; 
Artifact wrap(const Amber& amber) 
{ 
Artifact artifact { amber, true, {} }; 
return artifact; 
} 
Artifact onSuccess(const AmberTask& task, 
const Artifact& artifact) { 
// eval() when artifact.success == true. 
// otherwise, return an old artifact. 
} 
Artifact anyway(const AmberTask& task, 
const Artifact& artifact) { 
// no check of previous task success. 
// just safely eval() a new task. 
}
Как может выглядеть eval() 
Artifact eval(const AmberTask& task, const Artifact& artifact) { 
Artifact newArtifact = artifact; 
try { 
Amber newAmber = task(artifact.amber); 
newArtifact.amber = newAmber; 
newArtifact.success = true; 
} 
catch (const std::exception& e) { 
// Do something with e 
newArtifact = artifact; 
newArtifact.success = false; 
} 
return newArtifact; 
}
Обобщение безопасного типа 
// Было: 
struct Artifact { 
Amber amber; 
bool success; 
}; 
AmberTask goNorthTask = [](const Amber& amber) { 
Artifact action1Res = onSuccess (amberTask1, wrap(amber)); 
Artifact action2Res = onSuccess (amberTask2, action1Res); 
Artifact action3Res = onSuccess (amberTask3, action2Res); 
return action3Res.amber; 
};
Обобщение безопасного типа 
// Было: 
struct Artifact { 
Amber amber; 
bool success; 
}; 
// Стало: 
enum MaybeValue { 
Just, 
Nothing 
}; 
template <typename Data> 
struct Maybe { 
Data data; 
MaybeValue mValue; 
};
Обобщение безопасного типа 
// Было: 
Artifact wrap(const Amber& amber); 
Artifact onSuccess(const AmberTask& task, const Artifact& artifact); 
// Стало: 
template <typename Input> Maybe<Input> just(const Input& input); 
template <typename Input, typename Output> Maybe<Output> 
bind(const Maybe<Input>& input, 
const std::function<Maybe<Output>(Input)>& action);
Maybe - это монада 
template <typename Input, typename Output> Maybe<Output> 
bind(const Maybe<Input>& input, 
const std::function<Maybe<Output>(Input)>& action) { 
if (input.mValue == Nothing) { 
return nothing<Output>(); 
} 
return action(input.data); 
}
Монадические функции в Maybe 
const std::function<Maybe<ShadowVariator>(Amber)> 
lookupVariator = [](const Amber& amber) { 
return ...; // retrieve the nearest shadow's variator 
}; 
std::function<Maybe<Amber>(ShadowVariator)> 
applyVariator(const Amber& amber, 
Direction::DirectionType dir) { 
return [&amber, dir](const ShadowVariator& variator) { 
// apply variator to passed amber, using dir 
}; 
}
Использование Maybe 
MaybeAmber goDirectionBinded(const Amber& amber, 
Direction::DirectionType dir) { 
MaybeAmber mbAmber1 = just(amber); 
MaybeShadowVariator mbVariator = bind(mbAmber1, lookupVariator); 
MaybeAmber mbAmber2 = bind(mbVariator, applyVariator(amber, dir)); 
MaybeAmber mbAmber3 = bind(mbAmber2, updateNearestPlace); 
return mbAmber3; 
}
Использование Maybe с auto 
MaybeAmber goDirectionBinded(const Amber& amber, 
Direction::DirectionType dir) 
{ 
auto m1 = just(amber); 
auto m2 = bind(m1, lookupVariator); 
auto m3 = bind(m2, applyVariator(amber, dir)); 
auto m4 = bind(m3, updateNearestPlace); 
return m4; 
}
Связывание многих Maybe 
MaybeAmber goDirectionStacked(const Amber& amber, 
Direction::DirectionType dir) { 
MaybeActionStack<Amber, ShadowVariator, Amber, Amber> 
stack = bindMany(lookupVariator, 
applyVariator(amber, dir), 
updateNearestPlace); 
MaybeAmber mbAmber = evalMaybes(just(amber), stack); 
return mbAmber; 
}
Простая реализация MaybeActionStack 
template <typename M1, typename M2, 
typename M3, typename M4> 
struct MaybeActionStack 
{ 
std::function<Maybe<M2>(M1)> action1; 
std::function<Maybe<M3>(M2)> action2; 
std::function<Maybe<M4>(M3)> action3; 
};
Простая реализация bindMany 
template <typename M1, typename M2, typename M3, typename M4> 
MaybeActionStack<M1, M2, M3, M4> 
bindMany(const std::function<Maybe<M2>(M1)> action1, 
const std::function<Maybe<M3>(M2)> action2, 
const std::function<Maybe<M4>(M3)> action3) 
{ 
MaybeActionStack<M1, M2, M3, M4> stack; 
stack.action1 = action1; 
stack.action2 = action2; 
stack.action3 = action3; 
return stack; 
}
Простая реализация evalMaybes 
template <typename M1, typename M2, typename M3, typename M4> 
Maybe<M4> evalMaybes(const Maybe<M1>& m1, 
const MaybeActionStack<M1, M2, M3, M4>& stack) 
{ 
Maybe<M2> m2 = bind<M1, M2>(m1, stack.action1); 
Maybe<M3> m3 = bind<M2, M3>(m2, stack.action2); 
Maybe<M4> m4 = bind<M3, M4>(m3, stack.action3); 
return m4; 
}
Тестирование 
void Testing::changeElementTest() { 
amber::ShadowStructure structure = { { amber::Element::Ground, 90 
, { amber::Element::Water, 10 } }; 
amber::ShadowStructure expected = { { amber::Element::Ground, 100 } 
, { amber::Element::Water, 10 } }; 
auto newStructure = changeElement(structure, amber::Element::Ground, 10); 
ASSERT_EQ(expected, newStructure); 
}
Положительные моменты 
● Лямбды - универсальный инструмент дизайна 
● Краткость функционального кода 
● Высокая модульность 
● Прекрасная тестируемость 
● Редуцирована структурная сложность ПО 
● Многие задачи решаются проще, понятнее 
● Больше внимания задаче, а не борьбе с 
языком
Проблемы и особенности 
● Массированное копирование данных 
● Большее потребление памяти 
● Меньшая производительность 
● Опасные замыкания в лямбдах 
● Чистота функций не контролируется 
● Нет алгебраических типов данных 
● Нет каррирования, заменители плохи
C++ User Group, Новосибирск 
Мы это сделали, 
всем спасибо! :) 
Александр Гранин 
graninas@gmail.com
А теперь - бонус!
Проблема: глубокие структуры 
struct C { 
int intC; 
std::string stringC; 
}; 
int intC; 
std::string stringC; 
C 
B 
A 
struct B { 
C c; 
}; 
struct A { 
B b; 
}; 
// Not Ok: a mutable code 
void changeC(A& a) { 
a.b.c.intC += 20; 
a.b.c.stringC = "Hello, World!"; 
}
Проблема: глубокие структуры 
// Immutable code, but still not Ok: too deep structure diving 
A changeC(const A& oldA) { 
C newC = oldA.b.c; 
newC.intC = oldA.b.c.intC + 20; 
newC.stringC = "Hello, world!"; 
int intC; 
std::string stringC; 
C 
B 
A 
B newB = oldA.b; 
newB.c = newC; 
A newA = oldA; 
newA.b = newB; 
return newA; 
}
Встречайте: линзы! 
A changeC(const A &oldA) { 
LensStack<A, B, C> stack = zoom(aToBLens(), bToCLens()); 
A newA = evalLens(stack, oldA, modifyC); 
return newA; 
} 
std::function<C(C)> modifyC = [](const C& c) 
{ 
return C { c.intC + 20, "Hello, World!" }; 
};
Линза - это геттер + сеттер 
Lens<A, B> aToBLens() { 
return lens<A, B> ( GETTER(A, b) 
, SETTER(A, B, b)); 
} 
Lens<B, C> bToCLens() { 
return lens<B, C> ( GETTER(B, c) 
, SETTER(B, C, c)); 
}
Геттер и сеттер - это лямбды 
Lens<A, B> aToBLensDesugared() { 
return lens<A, B> 
( [](const A& a) { return a.b; } 
, [](const A& a, const B& b) { 
A newA = a; 
newA.b = b; 
return newA; 
}); 
}
LensStack - та же идея, что и 
MaybeActionStack 
template <typename Zoomed1, typename Zoomed2, typename 
Zoomed3 = Identity, typename Zoomed4 = Identity> 
struct LensStack 
{ 
Lens<Zoomed1, Zoomed2> lens1; 
Lens<Zoomed2, Zoomed3> lens2; 
Lens<Zoomed3, Zoomed4> lens3; 
};
Зуммирование и фокусировка 
template <typename Zoomed1, typename Zoomed2, 
typename Zoomed3> 
LensStack<Zoomed1, Zoomed2, Zoomed3, Identity> 
zoom(Lens<Zoomed1, Zoomed2> l1 
, Lens<Zoomed2, Zoomed3> l2) { 
LensStack<Zoomed1, Zoomed2, Zoomed3, Identity> ls; 
ls.lens1 = l1; 
ls.lens2 = l2; 
ls.lens3 = idL<Zoomed3>(); 
return ls; 
}
C++ User Group, Новосибирск 
На этот раз 
действительно все! 
Вопросы? 
Александр Гранин 
graninas@gmail.com

More Related Content

What's hot

Монады для барабанщиков. Антон Холомьёв
Монады для барабанщиков. Антон ХоломьёвМонады для барабанщиков. Антон Холомьёв
Монады для барабанщиков. Антон ХоломьёвЮрий Сыровецкий
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Mikhail Kurnosov
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Mikhail Matrosov
 
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Python Meetup
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsPlatonov Sergey
 
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Mikhail Kurnosov
 
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировкиЛекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировкиMikhail Kurnosov
 
DSLs in Lisp and Clojure
DSLs in Lisp and ClojureDSLs in Lisp and Clojure
DSLs in Lisp and ClojureVasil Remeniuk
 
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...CocoaHeads
 
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru GroupКак не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru GroupMail.ru Group
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython Meetup
 
Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур
 Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур  Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур
Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур it-people
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Mikhail Kurnosov
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 

What's hot (20)

Java8. Innovations
Java8. InnovationsJava8. Innovations
Java8. Innovations
 
Монады для барабанщиков. Антон Холомьёв
Монады для барабанщиков. Антон ХоломьёвМонады для барабанщиков. Антон Холомьёв
Монады для барабанщиков. Антон Холомьёв
 
Java 8. Lambdas
Java 8. LambdasJava 8. Lambdas
Java 8. Lambdas
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
 
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free maps
 
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
 
msumobi2. Лекция 1
msumobi2. Лекция 1msumobi2. Лекция 1
msumobi2. Лекция 1
 
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировкиЛекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
 
Intro to Swift techitout
Intro to Swift techitoutIntro to Swift techitout
Intro to Swift techitout
 
Clojure #2 (2014)
Clojure #2 (2014)Clojure #2 (2014)
Clojure #2 (2014)
 
DSLs in Lisp and Clojure
DSLs in Lisp and ClojureDSLs in Lisp and Clojure
DSLs in Lisp and Clojure
 
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
 
Clojure #1
Clojure #1Clojure #1
Clojure #1
 
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru GroupКак не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.by
 
Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур
 Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур  Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур
Кодогенерация на службе оптимизации, Игорь Чевдарь, СКБ Контур
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 

Similar to Александр Гранин, "Декларативно-функциональный дизайн на С++11"

C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному кодуVasiliy Deynega
 
Groovy presentation.
Groovy presentation.Groovy presentation.
Groovy presentation.Infinity
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Mikhail Kurnosov
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?Vasil Remeniuk
 
Ciklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScriptCiklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScriptDmytro Mindra
 
NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript Dmytro Mindra
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 
DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6Dmitry Soshnikov
 
Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grailsguest32215a
 
Ruby - или зачем мне еще один язык программирования?
Ruby - или зачем мне еще один язык программирования?Ruby - или зачем мне еще один язык программирования?
Ruby - или зачем мне еще один язык программирования?Pavel Tsukanov
 
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs ReflectionRoslyn API: SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs ReflectionDenis Tsvettsih
 
CodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидах
CodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидахCodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидах
CodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидахCodeFest
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1Eduard Antsupov
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Vasya Petrov
 
Web осень 2012 лекция 9
Web осень 2012 лекция 9Web осень 2012 лекция 9
Web осень 2012 лекция 9Technopark
 
Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиГлеб Тарасов
 

Similar to Александр Гранин, "Декларативно-функциональный дизайн на С++11" (20)

C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному коду
 
Groovy presentation.
Groovy presentation.Groovy presentation.
Groovy presentation.
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?
 
Ciklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScriptCiklum .NET Saturday - Introduction to TypeScript
Ciklum .NET Saturday - Introduction to TypeScript
 
NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript NetworkUA - 2012 - Introduction TypeScript
NetworkUA - 2012 - Introduction TypeScript
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6DevConf. Дмитрий Сошников - ECMAScript 6
DevConf. Дмитрий Сошников - ECMAScript 6
 
Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grails
 
Ruby - или зачем мне еще один язык программирования?
Ruby - или зачем мне еще один язык программирования?Ruby - или зачем мне еще один язык программирования?
Ruby - или зачем мне еще один язык программирования?
 
Суперсилы Chrome developer tools
Суперсилы Chrome developer toolsСуперсилы Chrome developer tools
Суперсилы Chrome developer tools
 
Асинхронный JavaScript
Асинхронный JavaScriptАсинхронный JavaScript
Асинхронный JavaScript
 
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs ReflectionRoslyn API: SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
 
CodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидах
CodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидахCodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидах
CodeFest 2014. Пугачев С. — Язык TypeScript или JavaScript на стероидах
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
 
Web осень 2012 лекция 9
Web осень 2012 лекция 9Web осень 2012 лекция 9
Web осень 2012 лекция 9
 
Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с данными
 

More from Platonov Sergey

Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3Platonov Sergey
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Platonov Sergey
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Platonov Sergey
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеPlatonov Sergey
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxPlatonov Sergey
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIPlatonov Sergey
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IPlatonov Sergey
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практикеPlatonov Sergey
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутовPlatonov Sergey
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Platonov Sergey
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Platonov Sergey
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийPlatonov Sergey
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Platonov Sergey
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Platonov Sergey
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияPlatonov Sergey
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьPlatonov Sergey
 
DI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыDI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыPlatonov Sergey
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузераPlatonov Sergey
 

More from Platonov Sergey (20)

Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практике
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутов
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++
 
C++ exceptions
C++ exceptionsC++ exceptions
C++ exceptions
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычислений
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим жить
 
DI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыDI в C++ тонкости и нюансы
DI в C++ тонкости и нюансы
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузера
 

Александр Гранин, "Декларативно-функциональный дизайн на С++11"

  • 1. C++ User Group, Новосибирск Функционально-декларативный дизайн на С++ Александр Гранин graninas@gmail.com
  • 2. О себе ● C++ → Haskell ● Рассказывал на DevDay@2GIS о Haskell ● Рассказывал на TechTalks@NSU о ФП ● Статьи на Хабре о дизайне в ФП ● Работаю в “Лаборатории Касперского”
  • 3. struct Presentation { Описание задачи Функциональная комбинаторика Продвинутый дизайн Тестирование Проблемы и особенности };
  • 4. О задаче ● Игра “Амбер” (По мотивам “Хроник Амбера” Роджера Желязны) ● C++11 (Qt C++ 5.2.1, gcc 4.8.2) ● Функционально-декларативный дизайн ● Максимум смысла, минимум кода ● https://github.com/graninas/Amber
  • 5. Ограничения ● Нет классов, только struct (POD) ● Списки инициализации! ● Нет циклов for(;;), есть for_each() ● Всяческие eDSLs ● Иммутабельность ● Лямбды, функции, замыкания
  • 6. Структура Амбера Полюс Амбера Средние миры Полюс Хаоса Амбер Бергма Кашфа Авалон Земля Дворы Хаоса
  • 7. Координаты тени, игрока Полюс Амбера Амбер G(90) W(10) A(100) S(70) Бергма Кашфа Авалон G(30) W(70) A(80) S(90) Амбер: 90 Земля (G) 10 Вода (W) 100 Воздух (A) 70 Небо (S) 100 Флора 100 Фауна 0 Расстояние до Амбера 100 Расстояние до Хаоса
  • 8. Коородинаты тени, игрока namespace Element { enum ElementType { Air, Sky, Water, Ground }; } Амбер Бергма Кашфа Авалон Игрок: 90 Земля 10 Вода 100 Воздух 70 Небо typedef std::map<Element::ElementType, int> ShadowStructure;
  • 9. Декларативное задание координат ShadowStructure::value_type Air(int air) { return ShadowStructure::value_type(Element::Air, air); } ShadowStructure amberShadowStructure() { return { { Element::Ground, 90 } , { Element::Water, 10 } , Air(100) , Sky(70) }; }
  • 10. Определение тени typedef std::function<ShadowStructure(ShadowStructure, Direction::DirectionType)> ShadowVariator; struct Shadow { ShadowName name; ShadowVariator variator; ShadowStructure structure; double influence; };
  • 11. ShadowVariator координат игрока typedef std::function<ShadowStructure(ShadowStructure, Direction::DirectionType)> ShadowVariator; const ShadowVariator identityVariator = [](const ShadowStructure& structure, Direction::DirectionType) { return structure; }; N Ground S Water E Sky W Air
  • 12. ShadowVariator координат игрока const ShadowVariator bergmaVariator = [](const ShadowStructure& structure, Direction::DirectionType dir) -> ShadowStructure { switch (dir) { case Direction::North: return changeElements({ element::Water(-2) , element::Ground(2) } , structure); // and so on for the different directions... } };
  • 13. Игровой процесс Input Output Amber 1 AmberTask Evaluator AAmmbbeerTrTaasksk AmberTask Amber 2
  • 14. AmberTask - задачи на лямбдах typedef std::function<Amber (const Amber&)> AmberTask; const AmberTask goNorth = [](const Amber& amber) { const ShadowVariator variator = // somehow get variator Amber newAmber = amber; newAmber.playerPos = variator(amber.playerPos, Direction::North); return newAmber; };
  • 15. Список задач typedef std::function<Amber (const Amber&)> AmberTask; typedef std::list<AmberTask> AmberTaskList; Amber goNorth(const Amber& amber) { AmberTaskList tasks = { goNorth, inflateShadowStorms, tickWorldTime }; return evaluate(amber, tasks); }
  • 16. Выполнение списка задач typedef std::function<Amber (const Amber&)> AmberTask; typedef std::list<AmberTask> AmberTaskList; Amber evaluate(const Amber& amber, const AmberTaskList& tasks) { Amber currentAmber = amber; std::for_each(tasks.begin(), tasks.end(), [&currentAmber](const AmberTask& task) { currentAmber = task(currentAmber); }); return currentAmber; }
  • 17. Boilerplate const AmberTask goNorth = [](const Amber& amber) { // Bla-bla with Direction::North }; const AmberTask goSouth = [](const Amber& amber) { // The same Bla-bla with Direction::South }; // And so on...
  • 18. Конструирование лямбд AmberTask goDirection(Direction::DirectionType dir) { return [dir](const Amber& amber) { // Bla-bla with dir }; } AmberTaskList tasks = { goDirection(Direction::North), inflateShadowStorms, tickWorldTime };
  • 19. Небезопасный код const AmberTask inflateShadowStorms = [](const Amber& amber) { throw std::runtime_error("Shit happened! :)"); };
  • 20. Данные + результат onSuccess Task Amber 1 Result 1 Amber 2 if (Result 1 == Success) + - onFail Task safeEvalTask Result 2 safeEvalTask
  • 21. Комбинаторный eDSL const AmberTask tickOneAmberHour = [](const Amber& amber) { auto action1Res = anyway (inflateShadowStorms, wrap(amber)); auto action2Res = onSuccess (affectShadowStorms, action1Res); auto action3Res = onFail (shadowStabilization, action2Res); auto action4Res = anyway (tickWorldTime, action3Res); return action4Res.amber; }; AmberTask goNorthTask = [](const Amber& amber) { auto action1Res = anyway (goNorth, wrap(amber)); auto action2Res = anyway (tickOneAmberHour, action1Res); return action2Res.amber; };
  • 22. Комбинаторы struct Artifact { Amber amber; bool success; }; Artifact wrap(const Amber& amber) { Artifact artifact { amber, true, {} }; return artifact; } Artifact onSuccess(const AmberTask& task, const Artifact& artifact) { // eval() when artifact.success == true. // otherwise, return an old artifact. } Artifact anyway(const AmberTask& task, const Artifact& artifact) { // no check of previous task success. // just safely eval() a new task. }
  • 23. Как может выглядеть eval() Artifact eval(const AmberTask& task, const Artifact& artifact) { Artifact newArtifact = artifact; try { Amber newAmber = task(artifact.amber); newArtifact.amber = newAmber; newArtifact.success = true; } catch (const std::exception& e) { // Do something with e newArtifact = artifact; newArtifact.success = false; } return newArtifact; }
  • 24. Обобщение безопасного типа // Было: struct Artifact { Amber amber; bool success; }; AmberTask goNorthTask = [](const Amber& amber) { Artifact action1Res = onSuccess (amberTask1, wrap(amber)); Artifact action2Res = onSuccess (amberTask2, action1Res); Artifact action3Res = onSuccess (amberTask3, action2Res); return action3Res.amber; };
  • 25. Обобщение безопасного типа // Было: struct Artifact { Amber amber; bool success; }; // Стало: enum MaybeValue { Just, Nothing }; template <typename Data> struct Maybe { Data data; MaybeValue mValue; };
  • 26. Обобщение безопасного типа // Было: Artifact wrap(const Amber& amber); Artifact onSuccess(const AmberTask& task, const Artifact& artifact); // Стало: template <typename Input> Maybe<Input> just(const Input& input); template <typename Input, typename Output> Maybe<Output> bind(const Maybe<Input>& input, const std::function<Maybe<Output>(Input)>& action);
  • 27. Maybe - это монада template <typename Input, typename Output> Maybe<Output> bind(const Maybe<Input>& input, const std::function<Maybe<Output>(Input)>& action) { if (input.mValue == Nothing) { return nothing<Output>(); } return action(input.data); }
  • 28. Монадические функции в Maybe const std::function<Maybe<ShadowVariator>(Amber)> lookupVariator = [](const Amber& amber) { return ...; // retrieve the nearest shadow's variator }; std::function<Maybe<Amber>(ShadowVariator)> applyVariator(const Amber& amber, Direction::DirectionType dir) { return [&amber, dir](const ShadowVariator& variator) { // apply variator to passed amber, using dir }; }
  • 29. Использование Maybe MaybeAmber goDirectionBinded(const Amber& amber, Direction::DirectionType dir) { MaybeAmber mbAmber1 = just(amber); MaybeShadowVariator mbVariator = bind(mbAmber1, lookupVariator); MaybeAmber mbAmber2 = bind(mbVariator, applyVariator(amber, dir)); MaybeAmber mbAmber3 = bind(mbAmber2, updateNearestPlace); return mbAmber3; }
  • 30. Использование Maybe с auto MaybeAmber goDirectionBinded(const Amber& amber, Direction::DirectionType dir) { auto m1 = just(amber); auto m2 = bind(m1, lookupVariator); auto m3 = bind(m2, applyVariator(amber, dir)); auto m4 = bind(m3, updateNearestPlace); return m4; }
  • 31. Связывание многих Maybe MaybeAmber goDirectionStacked(const Amber& amber, Direction::DirectionType dir) { MaybeActionStack<Amber, ShadowVariator, Amber, Amber> stack = bindMany(lookupVariator, applyVariator(amber, dir), updateNearestPlace); MaybeAmber mbAmber = evalMaybes(just(amber), stack); return mbAmber; }
  • 32. Простая реализация MaybeActionStack template <typename M1, typename M2, typename M3, typename M4> struct MaybeActionStack { std::function<Maybe<M2>(M1)> action1; std::function<Maybe<M3>(M2)> action2; std::function<Maybe<M4>(M3)> action3; };
  • 33. Простая реализация bindMany template <typename M1, typename M2, typename M3, typename M4> MaybeActionStack<M1, M2, M3, M4> bindMany(const std::function<Maybe<M2>(M1)> action1, const std::function<Maybe<M3>(M2)> action2, const std::function<Maybe<M4>(M3)> action3) { MaybeActionStack<M1, M2, M3, M4> stack; stack.action1 = action1; stack.action2 = action2; stack.action3 = action3; return stack; }
  • 34. Простая реализация evalMaybes template <typename M1, typename M2, typename M3, typename M4> Maybe<M4> evalMaybes(const Maybe<M1>& m1, const MaybeActionStack<M1, M2, M3, M4>& stack) { Maybe<M2> m2 = bind<M1, M2>(m1, stack.action1); Maybe<M3> m3 = bind<M2, M3>(m2, stack.action2); Maybe<M4> m4 = bind<M3, M4>(m3, stack.action3); return m4; }
  • 35. Тестирование void Testing::changeElementTest() { amber::ShadowStructure structure = { { amber::Element::Ground, 90 , { amber::Element::Water, 10 } }; amber::ShadowStructure expected = { { amber::Element::Ground, 100 } , { amber::Element::Water, 10 } }; auto newStructure = changeElement(structure, amber::Element::Ground, 10); ASSERT_EQ(expected, newStructure); }
  • 36. Положительные моменты ● Лямбды - универсальный инструмент дизайна ● Краткость функционального кода ● Высокая модульность ● Прекрасная тестируемость ● Редуцирована структурная сложность ПО ● Многие задачи решаются проще, понятнее ● Больше внимания задаче, а не борьбе с языком
  • 37. Проблемы и особенности ● Массированное копирование данных ● Большее потребление памяти ● Меньшая производительность ● Опасные замыкания в лямбдах ● Чистота функций не контролируется ● Нет алгебраических типов данных ● Нет каррирования, заменители плохи
  • 38. C++ User Group, Новосибирск Мы это сделали, всем спасибо! :) Александр Гранин graninas@gmail.com
  • 39. А теперь - бонус!
  • 40. Проблема: глубокие структуры struct C { int intC; std::string stringC; }; int intC; std::string stringC; C B A struct B { C c; }; struct A { B b; }; // Not Ok: a mutable code void changeC(A& a) { a.b.c.intC += 20; a.b.c.stringC = "Hello, World!"; }
  • 41. Проблема: глубокие структуры // Immutable code, but still not Ok: too deep structure diving A changeC(const A& oldA) { C newC = oldA.b.c; newC.intC = oldA.b.c.intC + 20; newC.stringC = "Hello, world!"; int intC; std::string stringC; C B A B newB = oldA.b; newB.c = newC; A newA = oldA; newA.b = newB; return newA; }
  • 42. Встречайте: линзы! A changeC(const A &oldA) { LensStack<A, B, C> stack = zoom(aToBLens(), bToCLens()); A newA = evalLens(stack, oldA, modifyC); return newA; } std::function<C(C)> modifyC = [](const C& c) { return C { c.intC + 20, "Hello, World!" }; };
  • 43. Линза - это геттер + сеттер Lens<A, B> aToBLens() { return lens<A, B> ( GETTER(A, b) , SETTER(A, B, b)); } Lens<B, C> bToCLens() { return lens<B, C> ( GETTER(B, c) , SETTER(B, C, c)); }
  • 44. Геттер и сеттер - это лямбды Lens<A, B> aToBLensDesugared() { return lens<A, B> ( [](const A& a) { return a.b; } , [](const A& a, const B& b) { A newA = a; newA.b = b; return newA; }); }
  • 45. LensStack - та же идея, что и MaybeActionStack template <typename Zoomed1, typename Zoomed2, typename Zoomed3 = Identity, typename Zoomed4 = Identity> struct LensStack { Lens<Zoomed1, Zoomed2> lens1; Lens<Zoomed2, Zoomed3> lens2; Lens<Zoomed3, Zoomed4> lens3; };
  • 46. Зуммирование и фокусировка template <typename Zoomed1, typename Zoomed2, typename Zoomed3> LensStack<Zoomed1, Zoomed2, Zoomed3, Identity> zoom(Lens<Zoomed1, Zoomed2> l1 , Lens<Zoomed2, Zoomed3> l2) { LensStack<Zoomed1, Zoomed2, Zoomed3, Identity> ls; ls.lens1 = l1; ls.lens2 = l2; ls.lens3 = idL<Zoomed3>(); return ls; }
  • 47. C++ User Group, Новосибирск На этот раз действительно все! Вопросы? Александр Гранин graninas@gmail.com