SlideShare a Scribd company logo
1 of 46
Download to read offline
Functional Microscope:
Lenses in С++
Alexander Granin
graninas@gmail.com
C++ Siberia, Novosibirsk
Me?
● C++, Haskell, C#
● C++ User Group Novosibirsk, 2014
● Talks, articles, FP evangelism...
● LambdaNsk - Novosibirsk FP-community
● Kaspersky Lab
struct Presentation
{
FP in C++?..
Functional Lenses
cpp_lenses library
};
4
FP in C++?..
С++ User Group Novosibirsk, 2014
FP concepts in C++
● Lambdas, closures, functions (almost pure)
● Immutability, POD-types
● Templates - pure functional language
● FTL - Functional Template Library
● Initialization lists
● for_each(), recursion
7
Functional Lenses
Lens 2 Lens 3Lens 1
8
Matryoshka
struct Account { Person person; };
struct Person { Address address; };
struct Address
{
std::string street;
int house;
int flat;
};
9
Mutable variables...
void setStreet(Account& account, const std::string& newStreet)
{
account.person.address.street = newStreet;
}
10
void setStreet(Account& account, const std::string& newStreet)
{
account.person.address.street = newStreet;
}
Mutable variables...
● Easy to break the client code
● Demetra law is violated
● Highly specific code
● Boilerplate
11
Mutable state...
void Account::setStreet(const std::string& newStreet)
{
this->person.address.street = newStreet;
}
12
Mutable state...
void Account::setStreet(const std::string& newStreet)
{
this->person.address.street = newStreet;
}
● Demetra law is violated
● Highly specific code
● Mixing of different layers
● SRP is violated
● Not a POD type
13
Account setStreet(Account account, const std::string& newStreet)
{
account.person.address.street = newStreet;
return account;
}
Immutable approach…
14
Account setStreet(Account account, const std::string& newStreet)
{
account.person.address.street = newStreet;
return account;
}
Immutable approach… Not so good.
● Easy to break the client code
● Demetra law is violated
● Highly specific code
● Boilerplate
Ok, Lenses!
auto lens = zoom(personLens, addressLens, streetLens);
auto newAccount = set(lens, oldAccount, std::string("New street"));
● “Focused” internal element of the structure
● Do something with the element from outside
● Hiding data structure realization
● Fully immutable, composable and reusable
Ok, Lenses!
auto lens = zoom(personLens, addressLens, streetLens);
auto newAccount = set(lens, oldAccount, std::string("New street"));
So, how does this work?
Open matryoshka, pull out matryoshka...
Account account = {...};
Person person = getPerson(account);
Address address = getAddress(person);
std::string street = getStreet(address);
std::string newStreet = "Churchill's " + street;
Address newAddress = setStreet(address, newStreet);
Person newPerson = setAddress(person, newAddress);
Account newAccount = setPerson(account, newPerson);
Person getPerson(const Account& account) {
return account.person;
}
Account setPerson(Account account, const Person& person) {
account.person = person;
return account;
}
getA(), setA()
auto getPerson = [](const Account& account) {
return account.person;
};
auto setPerson = [](Account account, const Person& person) {
account.person = person;
return account;
};
Getter, Setter
auto getPerson = [](const Account& account) {
return account.person;
};
auto setPerson = [](Account account, const Person& person) {
account.person = person;
return account;
};
Getter, Setter
std::function<Focus(Value)> getter;
std::function<Value(Value, Focus)> setter;
template <typename Value, typename Focus>
struct Lens {
std::function<Focus(Value)> getter;
std::function<Value(Value, Focus)> setter;
};
Lens<Account, Person> personLens = { getPerson, setPerson };
Lens = Getter + Setter
view
template <typename Value, typename Focus>
Focus view(const Lens<Value, Focus>& lens, const Value& value) {
return lens.getter(value);
}
Lens<Account, Person> personLens = { getPerson, setPerson };
Person person = view(personLens, someAccount);
set
template <typename Value, typename Focus>
Value set(const Lens<Value, Focus>& lens, const Value& value,
const Focus& newFocus) {
return l.setter(value, newFocus);
}
Lens<Account, Person> personLens = { getPerson, setPerson };
Person person = view(personLens, someAccount);
Account newAccount = set(personLens, account, Person(”Santa”, ”Claus”));
Lens composition is Lens too
Lens<Account, Person> personLens = { getPerson, setPerson };
Lens<Person, Address> addressLens = { getAddress, setAddress };
Lens<Address, std::string> streetLens = { getStreet, setStreet };
auto lens = zoom(personLens, addressLens, streetLens); // Magic zoom!
Account newAccount = set(lens, someAccount, std::string(”Churchill's”));
Lens composition is Lens too
Lens<Account, Person> personLens = { getPerson, setPerson };
Lens<Person, Address> addressLens = { getAddress, setAddress };
Lens<Address, std::string> streetLens = { getStreet, setStreet };
auto lens = zoom(personLens, addressLens, streetLens); // Magic zoom!
// getPerson, getAddress, setStreet, setAddress, setPerson
Account newAccount = set(lens, someAccount, std::string(”Churchill's”));
26
cpp_lens library
Manual lenses
template <typename Value, typename Focus>
Lens<Value, Focus> lens(const std::function<Focus(Value)>& getter,
const std::function<Value(Value, Focus)>& setter) {
Lens<Value, Focus> l;
l.getter = getter;
l.setter = setter;
return l;
}
auto personL = lens<Account, Person>(
[](const Account& a) { return a.person; },
[](Account a, const Person& p) { a.person = p; return a; });
Autolenses
struct Account {
Person person;
std::string login;
std::string password;
};
#define MK_LENS(A, B, member) Lens<A, B> member##L() { 
return lens<A, B> ( GETTER(A, member), SETTER(A, B, member)); }
MK_LENS(Account, Person, person) // personL()
MK_LENS(Account, std::string, login) // loginL()
MK_LENS(Account, std::string, password) // passwordL()
zoom
Lens<A, B> lens = aToB;
???<A, B, C> lens = zoom(aToB, bToC);
???<A, B, C, D> lens = zoom(aToB, bToC, cToD);
zoom (not generic) -> LensStack
Lens<A, B> lens = aToB;
LensStack<A, B, C> lens = zoom(aToB, bToC);
LensStack<A, B, C, D> lens = zoom(aToB, bToC, cToD);
template <typename A, typename B, typename C>
LensStack<A, B, C> zoom(...) { … }
template <typename A, typename B, typename C, typename D>
LensStack<A, B, C, D> zoom(...) { ... }
LensStack (not generic)
template <typename A, typename B, typename C = Id, typename D = Id>
struct LensStack {
Lens<A, B> lens1;
Lens<B, C> lens2;
Lens<C, D> lens3;
};
LensStack<A, B, C> lens = zoom(aToB, bToC); // OK
LensStack<A, B, C, D> lens = zoom(aToB, bToC, cToD); // OK
LensStack<A, B, C, D, E> lens = zoom(aToB, bToC, cToD, dToE); // Ooops!
LensStack: Variadic Templates + magic
template<typename L, typename... Tail>
struct LensStack<L, Tail...> : LensStack<Tail...>
{
typedef LensStack<Tail...> base_type;
LensStack(L lens, Tail... tail)
: LensStack<Tail...>(tail...)
, m_lens(lens) {}
base_type& m_base = static_cast<base_type&>(*this);
L m_lens;
};
Infix literal `to` combinator!
auto lens1 = addressL to houseL;
auto lens2 = personL to lens1;
auto lens3 = aL to bL to cL to dL to … to theLastOneLens;
auto lens = (a to b) to c; // OK, left-associative
auto lens = a to (b to c); // Error
`to`: proxy + overloading + reroll stack
struct Proxy {...} proxy;
template <typename L1, typename L2>
LensStack<Lens<L1, L2>> operator<(const Lens<L1, L2>& lens, const Proxy&)
{ return LensStack<Lens<L1, L2>>(lens); }
template <typename LS, typename L>
typename LS::template reroll_type<L> operator>(const LS& stack, const L& lens)
{ return stack.reroll(lens); }
// `Infix literal operator` trick
#define to < proxy >
set
auto lens = personL() to addressL() to houseL();
Account account1 = {...};
Account account2 = set(lens, account1, 20); // house == 20
set, over
auto lens = personL() to addressL() to houseL();
Account account1 = {...};
Account account2 = set(lens, account1, 20); // house == 20
std::function<int(int)> modifier = [](int old) { return old + 6; };
Account account3 = over(lens, account2, modifier); // house == 26
What about containers?
struct Car { std::string model; };
std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} };
toListOf *
struct Car { std::string model; };
std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} };
std::list<std::string> result = toListOf(folded<Car>() to modelL(), cars);
// result: {"Ford Focus", "Toyota Corolla"}
* toListOf() and folded<T>() is a hack now, sorry...
traversed
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
traversed + set
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
Account newAccount1 = set(toCarL to modelL(), oldAccount, std::string(“Toyota”));
traversed + over
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
Account newAccount1 = set(toCarL to modelL(), oldAccount, std::string(“Toyota”));
std::function<std::string(std::string)> modifier = [](int old) { return old + 6; };
Account newAccount2 = over(toCarL to numberL(), newAccount1, modifier);
traversed + traversed!
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number;
std::list<std::string> accessories; };
auto toAccessoryL = personL() to carsL() to traversed<Car>()
to accessoriesL() to traversed<std::string>();
cpp_lenses library
● Highly experimental
● Done: composing; set, view, over, traverse
● TODO: filter, traverse++, fold, prisms, fusion…
● TODO: clean it, make it wise, short and robust
● github.com/graninas/cpp_lenses
● Complex structures processing
● Test data preparation
● Some XPath, LINQ analogue
● Functional approach
● Much better than just <algorithm>
● ...Why not? Functional C++ is reality coming now
Why lenses in C++?
Thank you!
Alexander Granin
graninas@gmail.com
Any questions?
C++ Siberia, Novosibirsk
Rerolling LensStack
template<typename L1, typename... Tail>
struct LS<L1, Tail...> : LS<Tail...>
{
template <typename Reroll, typename Lx>
void reroll_(Reroll& rerolled, const Lx& lx) const
{
rerolled.m_lens = m_lens;
base.reroll_(rerolled.base, lx);
}
template <typename Lx>
LensStack<L1, Tail..., Lx> reroll(const Lx& lx) const
{
LensStack<L1, Tail..., Lx> rerolled;
rerolled.m_lens = m_lens;
base.reroll_(rerolled.base, lx);
return rerolled;
}
}
// Recursion base
template <typename... Tail>
struct LensStack
{
template <typename Reroll, typename Lx>
void reroll_(Reroll& rerolled, const Lx& lx)
{
rerolled.m_lens = lx;
}
};

More Related Content

What's hot (20)

Java 8 features
Java 8 featuresJava 8 features
Java 8 features
 
Dependency injection presentation
Dependency injection presentationDependency injection presentation
Dependency injection presentation
 
javascript objects
javascript objectsjavascript objects
javascript objects
 
Refactoring
RefactoringRefactoring
Refactoring
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Design Patterns Illustrated
Design Patterns IllustratedDesign Patterns Illustrated
Design Patterns Illustrated
 
Inheritance C#
Inheritance C#Inheritance C#
Inheritance C#
 
Dependency injection ppt
Dependency injection pptDependency injection ppt
Dependency injection ppt
 
Properties and indexers in C#
Properties and indexers in C#Properties and indexers in C#
Properties and indexers in C#
 
Proxy Design Pattern
Proxy Design PatternProxy Design Pattern
Proxy Design Pattern
 
Encapsulation
EncapsulationEncapsulation
Encapsulation
 
Vectors in Java
Vectors in JavaVectors in Java
Vectors in Java
 
Declarative UIs with Jetpack Compose
Declarative UIs with Jetpack ComposeDeclarative UIs with Jetpack Compose
Declarative UIs with Jetpack Compose
 
Builder pattern
Builder patternBuilder pattern
Builder pattern
 
PHP MVC
PHP MVCPHP MVC
PHP MVC
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Introduction to java beans
Introduction to java beansIntroduction to java beans
Introduction to java beans
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the Things
 
Adapter pattern
Adapter patternAdapter pattern
Adapter pattern
 
OOP java
OOP javaOOP java
OOP java
 

Similar to Functional microscope - Lenses in C++

Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! aleks-f
 
Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»SpbDotNet Community
 
GECon2017_Cpp a monster that no one likes but that will outlast them all _Ya...
GECon2017_Cpp  a monster that no one likes but that will outlast them all _Ya...GECon2017_Cpp  a monster that no one likes but that will outlast them all _Ya...
GECon2017_Cpp a monster that no one likes but that will outlast them all _Ya...GECon_Org Team
 
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them allGECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them allYauheni Akhotnikau
 
C++: Constructor, Copy Constructor and Assignment operator
C++: Constructor, Copy Constructor and Assignment operatorC++: Constructor, Copy Constructor and Assignment operator
C++: Constructor, Copy Constructor and Assignment operatorJussi Pohjolainen
 
CPP Language Basics - Reference
CPP Language Basics - ReferenceCPP Language Basics - Reference
CPP Language Basics - ReferenceMohammed Sikander
 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012aleks-f
 
What's new in C# 6 - NetPonto Porto 20160116
What's new in C# 6  - NetPonto Porto 20160116What's new in C# 6  - NetPonto Porto 20160116
What's new in C# 6 - NetPonto Porto 20160116Paulo Morgado
 
I want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdfI want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdfbermanbeancolungak45
 
Getting started with ES6
Getting started with ES6Getting started with ES6
Getting started with ES6Nitay Neeman
 
Arquitetura Java em 2007 (Java Architecture in 2007)
Arquitetura Java em 2007 (Java Architecture in 2007)Arquitetura Java em 2007 (Java Architecture in 2007)
Arquitetura Java em 2007 (Java Architecture in 2007)Phil Calçado
 

Similar to Functional microscope - Lenses in C++ (20)

Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! 
 
Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»
 
Bind me if you can
Bind me if you canBind me if you can
Bind me if you can
 
GECon2017_Cpp a monster that no one likes but that will outlast them all _Ya...
GECon2017_Cpp  a monster that no one likes but that will outlast them all _Ya...GECon2017_Cpp  a monster that no one likes but that will outlast them all _Ya...
GECon2017_Cpp a monster that no one likes but that will outlast them all _Ya...
 
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them allGECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
 
C++: Constructor, Copy Constructor and Assignment operator
C++: Constructor, Copy Constructor and Assignment operatorC++: Constructor, Copy Constructor and Assignment operator
C++: Constructor, Copy Constructor and Assignment operator
 
New C# features
New C# featuresNew C# features
New C# features
 
greenDAO
greenDAOgreenDAO
greenDAO
 
C to perl binding
C to perl bindingC to perl binding
C to perl binding
 
CPP Language Basics - Reference
CPP Language Basics - ReferenceCPP Language Basics - Reference
CPP Language Basics - Reference
 
Day 1
Day 1Day 1
Day 1
 
Functional C++
Functional C++Functional C++
Functional C++
 
The STL
The STLThe STL
The STL
 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012
 
What's new in C# 6 - NetPonto Porto 20160116
What's new in C# 6  - NetPonto Porto 20160116What's new in C# 6  - NetPonto Porto 20160116
What's new in C# 6 - NetPonto Porto 20160116
 
I want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdfI want help in the following C++ programming task. Please do coding .pdf
I want help in the following C++ programming task. Please do coding .pdf
 
ECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScriptECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScript
 
Oops presentation
Oops presentationOops presentation
Oops presentation
 
Getting started with ES6
Getting started with ES6Getting started with ES6
Getting started with ES6
 
Arquitetura Java em 2007 (Java Architecture in 2007)
Arquitetura Java em 2007 (Java Architecture in 2007)Arquitetura Java em 2007 (Java Architecture in 2007)
Arquitetura Java em 2007 (Java Architecture in 2007)
 

More from Alexander Granin

Concurrent applications with free monads and stm
Concurrent applications with free monads and stmConcurrent applications with free monads and stm
Concurrent applications with free monads and stmAlexander Granin
 
Hierarchical free monads and software design in fp
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fpAlexander Granin
 
Final tagless vs free monad
Final tagless vs free monadFinal tagless vs free monad
Final tagless vs free monadAlexander Granin
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++Alexander Granin
 
О разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentAlexander Granin
 
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...Alexander Granin
 
Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...Alexander Granin
 
Закон Деметры / Demetra's law
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's lawAlexander Granin
 
Design of big applications in FP
Design of big applications in FPDesign of big applications in FP
Design of big applications in FPAlexander Granin
 
GitHub - зеркало разработчика
GitHub - зеркало разработчикаGitHub - зеркало разработчика
GitHub - зеркало разработчикаAlexander Granin
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++Alexander Granin
 
Functional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskAlexander Granin
 
Transition graph using free monads and existentials
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentialsAlexander Granin
 
Software transactional memory. pure functional approach
Software transactional memory. pure functional approachSoftware transactional memory. pure functional approach
Software transactional memory. pure functional approachAlexander Granin
 
Вы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FPВы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FPAlexander Granin
 
Functional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsAlexander Granin
 
Дизайн больших приложений в ФП
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФПAlexander Granin
 
Линзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция даннымиЛинзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция даннымиAlexander Granin
 
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)Alexander Granin
 

More from Alexander Granin (20)

Concurrent applications with free monads and stm
Concurrent applications with free monads and stmConcurrent applications with free monads and stm
Concurrent applications with free monads and stm
 
Hierarchical free monads and software design in fp
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fp
 
Final tagless vs free monad
Final tagless vs free monadFinal tagless vs free monad
Final tagless vs free monad
 
Monadic parsers in C++
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++
 
О разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop development
 
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...
 
Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...
 
Закон Деметры / Demetra's law
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's law
 
Design of big applications in FP
Design of big applications in FPDesign of big applications in FP
Design of big applications in FP
 
GitHub - зеркало разработчика
GitHub - зеркало разработчикаGitHub - зеркало разработчика
GitHub - зеркало разработчика
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++
 
Functional programming in C++ LambdaNsk
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
 
Transition graph using free monads and existentials
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentials
 
Software transactional memory. pure functional approach
Software transactional memory. pure functional approachSoftware transactional memory. pure functional approach
Software transactional memory. pure functional approach
 
Вы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FPВы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FP
 
Functional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonads
 
Дизайн больших приложений в ФП
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФП
 
Линзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция даннымиЛинзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция данными
 
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)
 

Recently uploaded

Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 

Recently uploaded (20)

Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 

Functional microscope - Lenses in C++

  • 1. Functional Microscope: Lenses in С++ Alexander Granin graninas@gmail.com C++ Siberia, Novosibirsk
  • 2. Me? ● C++, Haskell, C# ● C++ User Group Novosibirsk, 2014 ● Talks, articles, FP evangelism... ● LambdaNsk - Novosibirsk FP-community ● Kaspersky Lab
  • 3. struct Presentation { FP in C++?.. Functional Lenses cpp_lenses library };
  • 5. С++ User Group Novosibirsk, 2014
  • 6. FP concepts in C++ ● Lambdas, closures, functions (almost pure) ● Immutability, POD-types ● Templates - pure functional language ● FTL - Functional Template Library ● Initialization lists ● for_each(), recursion
  • 8. 8 Matryoshka struct Account { Person person; }; struct Person { Address address; }; struct Address { std::string street; int house; int flat; };
  • 9. 9 Mutable variables... void setStreet(Account& account, const std::string& newStreet) { account.person.address.street = newStreet; }
  • 10. 10 void setStreet(Account& account, const std::string& newStreet) { account.person.address.street = newStreet; } Mutable variables... ● Easy to break the client code ● Demetra law is violated ● Highly specific code ● Boilerplate
  • 11. 11 Mutable state... void Account::setStreet(const std::string& newStreet) { this->person.address.street = newStreet; }
  • 12. 12 Mutable state... void Account::setStreet(const std::string& newStreet) { this->person.address.street = newStreet; } ● Demetra law is violated ● Highly specific code ● Mixing of different layers ● SRP is violated ● Not a POD type
  • 13. 13 Account setStreet(Account account, const std::string& newStreet) { account.person.address.street = newStreet; return account; } Immutable approach…
  • 14. 14 Account setStreet(Account account, const std::string& newStreet) { account.person.address.street = newStreet; return account; } Immutable approach… Not so good. ● Easy to break the client code ● Demetra law is violated ● Highly specific code ● Boilerplate
  • 15. Ok, Lenses! auto lens = zoom(personLens, addressLens, streetLens); auto newAccount = set(lens, oldAccount, std::string("New street")); ● “Focused” internal element of the structure ● Do something with the element from outside ● Hiding data structure realization ● Fully immutable, composable and reusable
  • 16. Ok, Lenses! auto lens = zoom(personLens, addressLens, streetLens); auto newAccount = set(lens, oldAccount, std::string("New street")); So, how does this work?
  • 17. Open matryoshka, pull out matryoshka... Account account = {...}; Person person = getPerson(account); Address address = getAddress(person); std::string street = getStreet(address); std::string newStreet = "Churchill's " + street; Address newAddress = setStreet(address, newStreet); Person newPerson = setAddress(person, newAddress); Account newAccount = setPerson(account, newPerson);
  • 18. Person getPerson(const Account& account) { return account.person; } Account setPerson(Account account, const Person& person) { account.person = person; return account; } getA(), setA()
  • 19. auto getPerson = [](const Account& account) { return account.person; }; auto setPerson = [](Account account, const Person& person) { account.person = person; return account; }; Getter, Setter
  • 20. auto getPerson = [](const Account& account) { return account.person; }; auto setPerson = [](Account account, const Person& person) { account.person = person; return account; }; Getter, Setter std::function<Focus(Value)> getter; std::function<Value(Value, Focus)> setter;
  • 21. template <typename Value, typename Focus> struct Lens { std::function<Focus(Value)> getter; std::function<Value(Value, Focus)> setter; }; Lens<Account, Person> personLens = { getPerson, setPerson }; Lens = Getter + Setter
  • 22. view template <typename Value, typename Focus> Focus view(const Lens<Value, Focus>& lens, const Value& value) { return lens.getter(value); } Lens<Account, Person> personLens = { getPerson, setPerson }; Person person = view(personLens, someAccount);
  • 23. set template <typename Value, typename Focus> Value set(const Lens<Value, Focus>& lens, const Value& value, const Focus& newFocus) { return l.setter(value, newFocus); } Lens<Account, Person> personLens = { getPerson, setPerson }; Person person = view(personLens, someAccount); Account newAccount = set(personLens, account, Person(”Santa”, ”Claus”));
  • 24. Lens composition is Lens too Lens<Account, Person> personLens = { getPerson, setPerson }; Lens<Person, Address> addressLens = { getAddress, setAddress }; Lens<Address, std::string> streetLens = { getStreet, setStreet }; auto lens = zoom(personLens, addressLens, streetLens); // Magic zoom! Account newAccount = set(lens, someAccount, std::string(”Churchill's”));
  • 25. Lens composition is Lens too Lens<Account, Person> personLens = { getPerson, setPerson }; Lens<Person, Address> addressLens = { getAddress, setAddress }; Lens<Address, std::string> streetLens = { getStreet, setStreet }; auto lens = zoom(personLens, addressLens, streetLens); // Magic zoom! // getPerson, getAddress, setStreet, setAddress, setPerson Account newAccount = set(lens, someAccount, std::string(”Churchill's”));
  • 27. Manual lenses template <typename Value, typename Focus> Lens<Value, Focus> lens(const std::function<Focus(Value)>& getter, const std::function<Value(Value, Focus)>& setter) { Lens<Value, Focus> l; l.getter = getter; l.setter = setter; return l; } auto personL = lens<Account, Person>( [](const Account& a) { return a.person; }, [](Account a, const Person& p) { a.person = p; return a; });
  • 28. Autolenses struct Account { Person person; std::string login; std::string password; }; #define MK_LENS(A, B, member) Lens<A, B> member##L() { return lens<A, B> ( GETTER(A, member), SETTER(A, B, member)); } MK_LENS(Account, Person, person) // personL() MK_LENS(Account, std::string, login) // loginL() MK_LENS(Account, std::string, password) // passwordL()
  • 29. zoom Lens<A, B> lens = aToB; ???<A, B, C> lens = zoom(aToB, bToC); ???<A, B, C, D> lens = zoom(aToB, bToC, cToD);
  • 30. zoom (not generic) -> LensStack Lens<A, B> lens = aToB; LensStack<A, B, C> lens = zoom(aToB, bToC); LensStack<A, B, C, D> lens = zoom(aToB, bToC, cToD); template <typename A, typename B, typename C> LensStack<A, B, C> zoom(...) { … } template <typename A, typename B, typename C, typename D> LensStack<A, B, C, D> zoom(...) { ... }
  • 31. LensStack (not generic) template <typename A, typename B, typename C = Id, typename D = Id> struct LensStack { Lens<A, B> lens1; Lens<B, C> lens2; Lens<C, D> lens3; }; LensStack<A, B, C> lens = zoom(aToB, bToC); // OK LensStack<A, B, C, D> lens = zoom(aToB, bToC, cToD); // OK LensStack<A, B, C, D, E> lens = zoom(aToB, bToC, cToD, dToE); // Ooops!
  • 32. LensStack: Variadic Templates + magic template<typename L, typename... Tail> struct LensStack<L, Tail...> : LensStack<Tail...> { typedef LensStack<Tail...> base_type; LensStack(L lens, Tail... tail) : LensStack<Tail...>(tail...) , m_lens(lens) {} base_type& m_base = static_cast<base_type&>(*this); L m_lens; };
  • 33. Infix literal `to` combinator! auto lens1 = addressL to houseL; auto lens2 = personL to lens1; auto lens3 = aL to bL to cL to dL to … to theLastOneLens; auto lens = (a to b) to c; // OK, left-associative auto lens = a to (b to c); // Error
  • 34. `to`: proxy + overloading + reroll stack struct Proxy {...} proxy; template <typename L1, typename L2> LensStack<Lens<L1, L2>> operator<(const Lens<L1, L2>& lens, const Proxy&) { return LensStack<Lens<L1, L2>>(lens); } template <typename LS, typename L> typename LS::template reroll_type<L> operator>(const LS& stack, const L& lens) { return stack.reroll(lens); } // `Infix literal operator` trick #define to < proxy >
  • 35. set auto lens = personL() to addressL() to houseL(); Account account1 = {...}; Account account2 = set(lens, account1, 20); // house == 20
  • 36. set, over auto lens = personL() to addressL() to houseL(); Account account1 = {...}; Account account2 = set(lens, account1, 20); // house == 20 std::function<int(int)> modifier = [](int old) { return old + 6; }; Account account3 = over(lens, account2, modifier); // house == 26
  • 37. What about containers? struct Car { std::string model; }; std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} };
  • 38. toListOf * struct Car { std::string model; }; std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} }; std::list<std::string> result = toListOf(folded<Car>() to modelL(), cars); // result: {"Ford Focus", "Toyota Corolla"} * toListOf() and folded<T>() is a hack now, sorry...
  • 39. traversed struct Account { Person person; }; struct Person { std::vector<Car> cars; }; struct Car { std::string model; int number; }; auto toCarL = personL() to carsL() to traversed<Car>();
  • 40. traversed + set struct Account { Person person; }; struct Person { std::vector<Car> cars; }; struct Car { std::string model; int number; }; auto toCarL = personL() to carsL() to traversed<Car>(); Account newAccount1 = set(toCarL to modelL(), oldAccount, std::string(“Toyota”));
  • 41. traversed + over struct Account { Person person; }; struct Person { std::vector<Car> cars; }; struct Car { std::string model; int number; }; auto toCarL = personL() to carsL() to traversed<Car>(); Account newAccount1 = set(toCarL to modelL(), oldAccount, std::string(“Toyota”)); std::function<std::string(std::string)> modifier = [](int old) { return old + 6; }; Account newAccount2 = over(toCarL to numberL(), newAccount1, modifier);
  • 42. traversed + traversed! struct Account { Person person; }; struct Person { std::vector<Car> cars; }; struct Car { std::string model; int number; std::list<std::string> accessories; }; auto toAccessoryL = personL() to carsL() to traversed<Car>() to accessoriesL() to traversed<std::string>();
  • 43. cpp_lenses library ● Highly experimental ● Done: composing; set, view, over, traverse ● TODO: filter, traverse++, fold, prisms, fusion… ● TODO: clean it, make it wise, short and robust ● github.com/graninas/cpp_lenses
  • 44. ● Complex structures processing ● Test data preparation ● Some XPath, LINQ analogue ● Functional approach ● Much better than just <algorithm> ● ...Why not? Functional C++ is reality coming now Why lenses in C++?
  • 45. Thank you! Alexander Granin graninas@gmail.com Any questions? C++ Siberia, Novosibirsk
  • 46. Rerolling LensStack template<typename L1, typename... Tail> struct LS<L1, Tail...> : LS<Tail...> { template <typename Reroll, typename Lx> void reroll_(Reroll& rerolled, const Lx& lx) const { rerolled.m_lens = m_lens; base.reroll_(rerolled.base, lx); } template <typename Lx> LensStack<L1, Tail..., Lx> reroll(const Lx& lx) const { LensStack<L1, Tail..., Lx> rerolled; rerolled.m_lens = m_lens; base.reroll_(rerolled.base, lx); return rerolled; } } // Recursion base template <typename... Tail> struct LensStack { template <typename Reroll, typename Lx> void reroll_(Reroll& rerolled, const Lx& lx) { rerolled.m_lens = lx; } };