Functional microscope - Lenses in C++

Alexander Granin
Alexander GraninSoftware Developer, Independent Consultant at Independent Consultant
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;
}
};
1 of 46

Recommended

Google BigQuery Servisi İle Büyük Veri İşlemleri Ve Sorgu Sonuçlarının BIME İ... by
Google BigQuery Servisi İle Büyük Veri İşlemleri Ve Sorgu Sonuçlarının BIME İ...Google BigQuery Servisi İle Büyük Veri İşlemleri Ve Sorgu Sonuçlarının BIME İ...
Google BigQuery Servisi İle Büyük Veri İşlemleri Ve Sorgu Sonuçlarının BIME İ...Cenk Derinozlu
3.1K views34 slides
What Is Express JS? by
What Is Express JS?What Is Express JS?
What Is Express JS?Simplilearn
469 views11 slides
Microservice's in detailed by
Microservice's in detailedMicroservice's in detailed
Microservice's in detailedMohammed Fazuluddin
9.5K views40 slides
Micro frontend by
Micro frontendMicro frontend
Micro frontendAmr Abd El Latief
407 views23 slides
Introduction to Graph Databases by
Introduction to Graph DatabasesIntroduction to Graph Databases
Introduction to Graph DatabasesMax De Marzi
80.9K views43 slides
Django에서 websocket을 사용하는 방법 by
Django에서 websocket을 사용하는 방법Django에서 websocket을 사용하는 방법
Django에서 websocket을 사용하는 방법NAVER D2
9.3K views29 slides

More Related Content

What's hot

Sqlite by
SqliteSqlite
SqliteRaghu nath
4.9K views121 slides
Device Twins, Digital Twins and Device Shadow by
Device Twins, Digital Twins and Device ShadowDevice Twins, Digital Twins and Device Shadow
Device Twins, Digital Twins and Device ShadowEstelle Auberix
3.1K views44 slides
Ux team organization by
Ux team organizationUx team organization
Ux team organizationDeidre Bohannon
17.6K views13 slides
Oops, I broke my API by
Oops, I broke my APIOops, I broke my API
Oops, I broke my APIiText Group nv
2.3K views76 slides
Tableau presentation by
Tableau presentationTableau presentation
Tableau presentationkt166212
41.3K views22 slides
Design Pattern - Factory Method Pattern by
Design Pattern - Factory Method PatternDesign Pattern - Factory Method Pattern
Design Pattern - Factory Method PatternMudasir Qazi
5.1K views13 slides

What's hot(20)

Device Twins, Digital Twins and Device Shadow by Estelle Auberix
Device Twins, Digital Twins and Device ShadowDevice Twins, Digital Twins and Device Shadow
Device Twins, Digital Twins and Device Shadow
Estelle Auberix3.1K views
Tableau presentation by kt166212
Tableau presentationTableau presentation
Tableau presentation
kt16621241.3K views
Design Pattern - Factory Method Pattern by Mudasir Qazi
Design Pattern - Factory Method PatternDesign Pattern - Factory Method Pattern
Design Pattern - Factory Method Pattern
Mudasir Qazi5.1K views
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ... by Edureka!
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
Edureka!1.3K views
Tableau Software - Business Analytics and Data Visualization by lesterathayde
Tableau Software - Business Analytics and Data VisualizationTableau Software - Business Analytics and Data Visualization
Tableau Software - Business Analytics and Data Visualization
lesterathayde33K views
"Introduction to Data Visualization" Workshop for General Assembly by Hunter ... by Hunter Whitney
"Introduction to Data Visualization" Workshop for General Assembly by Hunter ..."Introduction to Data Visualization" Workshop for General Assembly by Hunter ...
"Introduction to Data Visualization" Workshop for General Assembly by Hunter ...
Hunter Whitney3.2K views
Facebook Messenger/Whatsapp System Design by Elia Ahadi
Facebook Messenger/Whatsapp System DesignFacebook Messenger/Whatsapp System Design
Facebook Messenger/Whatsapp System Design
Elia Ahadi230 views
Power BI vs Tableau vs Cognos: A Data Analytics Research by Luciano Vilas Boas
Power BI vs Tableau vs Cognos: A Data Analytics ResearchPower BI vs Tableau vs Cognos: A Data Analytics Research
Power BI vs Tableau vs Cognos: A Data Analytics Research
Luciano Vilas Boas142 views
Python Developer Resume | Python Developer Skill Set, Jobs, Roles and Respons... by Edureka!
Python Developer Resume | Python Developer Skill Set, Jobs, Roles and Respons...Python Developer Resume | Python Developer Skill Set, Jobs, Roles and Respons...
Python Developer Resume | Python Developer Skill Set, Jobs, Roles and Respons...
Edureka!772 views
Getting Started with Google Data Studio by Chris Burgess
Getting Started with Google Data StudioGetting Started with Google Data Studio
Getting Started with Google Data Studio
Chris Burgess3.3K views
Client side scripting using Javascript by Bansari Shah
Client side scripting using JavascriptClient side scripting using Javascript
Client side scripting using Javascript
Bansari Shah191 views
Principles of MVC for Rails Developers by Edureka!
Principles of MVC for Rails DevelopersPrinciples of MVC for Rails Developers
Principles of MVC for Rails Developers
Edureka!1.6K views
UX Bootcamp Fall 2015 General Assembly by Jacklyn Burgan
UX Bootcamp Fall 2015 General AssemblyUX Bootcamp Fall 2015 General Assembly
UX Bootcamp Fall 2015 General Assembly
Jacklyn Burgan3.4K views

Similar to Functional microscope - Lenses in C++

Look Ma, “update DB to HTML5 using C++”, no hands!  by
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
2.3K views37 slides
Дмитрий Верескун «Синтаксический сахар C#» by
Дмитрий Верескун «Синтаксический сахар C#»Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»SpbDotNet Community
274 views35 slides
Bind me if you can by
Bind me if you canBind me if you can
Bind me if you canOvidiu Farauanu
32 views34 slides
GECon 2017: C++ - a Monster that no one likes but that will outlast them all by
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
1.9K views89 slides
GECon2017_Cpp a monster that no one likes but that will outlast them all _Ya... by
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
94 views89 slides
C++: Constructor, Copy Constructor and Assignment operator by
C++: Constructor, Copy Constructor and Assignment operatorC++: Constructor, Copy Constructor and Assignment operator
C++: Constructor, Copy Constructor and Assignment operatorJussi Pohjolainen
7.8K views38 slides

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

Look Ma, “update DB to HTML5 using C++”, no hands!  by aleks-f
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-f2.3K views
Дмитрий Верескун «Синтаксический сахар C#» by SpbDotNet Community
Дмитрий Верескун «Синтаксический сахар C#»Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»
GECon 2017: C++ - a Monster that no one likes but that will outlast them all by Yauheni Akhotnikau
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
Yauheni Akhotnikau1.9K views
GECon2017_Cpp a monster that no one likes but that will outlast them all _Ya... by GECon_Org Team
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 Team94 views
C++: Constructor, Copy Constructor and Assignment operator by Jussi Pohjolainen
C++: Constructor, Copy Constructor and Assignment operatorC++: Constructor, Copy Constructor and Assignment operator
C++: Constructor, Copy Constructor and Assignment operator
Jussi Pohjolainen7.8K views
Dynamic C++ Silicon Valley Code Camp 2012 by aleks-f
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012
aleks-f3.1K views
What's new in C# 6 - NetPonto Porto 20160116 by Paulo Morgado
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
Paulo Morgado1.4K views
Getting started with ES6 by Nitay Neeman
Getting started with ES6Getting started with ES6
Getting started with ES6
Nitay Neeman933 views
Arquitetura Java em 2007 (Java Architecture in 2007) by Phil Calçado
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çado1.9K views

More from Alexander Granin

Concurrent applications with free monads and stm by
Concurrent applications with free monads and stmConcurrent applications with free monads and stm
Concurrent applications with free monads and stmAlexander Granin
208 views55 slides
Hierarchical free monads and software design in fp by
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fpAlexander Granin
161 views59 slides
Final tagless vs free monad by
Final tagless vs free monadFinal tagless vs free monad
Final tagless vs free monadAlexander Granin
158 views74 slides
Monadic parsers in C++ by
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++Alexander Granin
579 views58 slides
The present and the future of functional programming in c++ by
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
343 views125 slides
О разработке десктопных приложений / About desktop development by
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop developmentAlexander Granin
437 views22 slides

More from Alexander Granin(20)

Concurrent applications with free monads and stm by Alexander Granin
Concurrent applications with free monads and stmConcurrent applications with free monads and stm
Concurrent applications with free monads and stm
Alexander Granin208 views
Hierarchical free monads and software design in fp by Alexander Granin
Hierarchical free monads and software design in fpHierarchical free monads and software design in fp
Hierarchical free monads and software design in fp
Alexander Granin161 views
The present and the future of functional programming in c++ by 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++
Alexander Granin343 views
О разработке десктопных приложений / About desktop development by Alexander Granin
О разработке десктопных приложений / About desktop developmentО разработке десктопных приложений / About desktop development
О разработке десктопных приложений / About desktop development
Alexander Granin437 views
Принципы и практики разработки ПО 2 / Principles and practices of software de... by Alexander Granin
Принципы и практики разработки ПО 2 / Principles and practices of software de...Принципы и практики разработки ПО 2 / Principles and practices of software de...
Принципы и практики разработки ПО 2 / Principles and practices of software de...
Alexander Granin133 views
Принципы и практики разработки ПО / Principles and practices of software deve... by Alexander Granin
Принципы и практики разработки ПО / Principles and practices of software deve...Принципы и практики разработки ПО / Principles and practices of software deve...
Принципы и практики разработки ПО / Principles and practices of software deve...
Alexander Granin140 views
Закон Деметры / Demetra's law by Alexander Granin
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's law
Alexander Granin149 views
GitHub - зеркало разработчика by Alexander Granin
GitHub - зеркало разработчикаGitHub - зеркало разработчика
GitHub - зеркало разработчика
Alexander Granin958 views
The Present and The Future of Functional Programming in C++ by 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++
Alexander Granin86 views
Functional programming in C++ LambdaNsk by Alexander Granin
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
Alexander Granin464 views
Transition graph using free monads and existentials by Alexander Granin
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentials
Alexander Granin473 views
Software transactional memory. pure functional approach by Alexander Granin
Software transactional memory. pure functional approachSoftware transactional memory. pure functional approach
Software transactional memory. pure functional approach
Alexander Granin968 views
Вы не понимаете ФП / You don't understand FP by Alexander Granin
Вы не понимаете ФП / You don't understand FPВы не понимаете ФП / You don't understand FP
Вы не понимаете ФП / You don't understand FP
Alexander Granin144 views
Functional "Life": parallel cellular automata and comonads by Alexander Granin
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonads
Alexander Granin885 views
Дизайн больших приложений в ФП by Alexander Granin
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФП
Alexander Granin761 views
Линзы - комбинаторная манипуляция данными by Alexander Granin
Линзы - комбинаторная манипуляция даннымиЛинзы - комбинаторная манипуляция данными
Линзы - комбинаторная манипуляция данными
Alexander Granin389 views
Линзы - комбинаторная манипуляция данными (Dev2Dev) by Alexander Granin
Линзы - комбинаторная манипуляция данными (Dev2Dev)Линзы - комбинаторная манипуляция данными (Dev2Dev)
Линзы - комбинаторная манипуляция данными (Dev2Dev)
Alexander Granin483 views

Recently uploaded

SAP FOR CONTRACT MANUFACTURING.pdf by
SAP FOR CONTRACT MANUFACTURING.pdfSAP FOR CONTRACT MANUFACTURING.pdf
SAP FOR CONTRACT MANUFACTURING.pdfVirendra Rai, PMP
11 views2 slides
Copilot Prompting Toolkit_All Resources.pdf by
Copilot Prompting Toolkit_All Resources.pdfCopilot Prompting Toolkit_All Resources.pdf
Copilot Prompting Toolkit_All Resources.pdfRiccardo Zamana
8 views4 slides
DevsRank by
DevsRankDevsRank
DevsRankdevsrank786
11 views1 slide
DSD-INT 2023 The Danube Hazardous Substances Model - Kovacs by
DSD-INT 2023 The Danube Hazardous Substances Model - KovacsDSD-INT 2023 The Danube Hazardous Substances Model - Kovacs
DSD-INT 2023 The Danube Hazardous Substances Model - KovacsDeltares
8 views17 slides
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx by
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptxanimuscrm
14 views19 slides
MariaDB stored procedures and why they should be improved by
MariaDB stored procedures and why they should be improvedMariaDB stored procedures and why they should be improved
MariaDB stored procedures and why they should be improvedFederico Razzoli
8 views32 slides

Recently uploaded(20)

Copilot Prompting Toolkit_All Resources.pdf by Riccardo Zamana
Copilot Prompting Toolkit_All Resources.pdfCopilot Prompting Toolkit_All Resources.pdf
Copilot Prompting Toolkit_All Resources.pdf
Riccardo Zamana8 views
DSD-INT 2023 The Danube Hazardous Substances Model - Kovacs by Deltares
DSD-INT 2023 The Danube Hazardous Substances Model - KovacsDSD-INT 2023 The Danube Hazardous Substances Model - Kovacs
DSD-INT 2023 The Danube Hazardous Substances Model - Kovacs
Deltares8 views
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx by animuscrm
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx
animuscrm14 views
MariaDB stored procedures and why they should be improved by Federico Razzoli
MariaDB stored procedures and why they should be improvedMariaDB stored procedures and why they should be improved
MariaDB stored procedures and why they should be improved
Tridens DevOps by Tridens
Tridens DevOpsTridens DevOps
Tridens DevOps
Tridens9 views
360 graden fabriek by info33492
360 graden fabriek360 graden fabriek
360 graden fabriek
info3349237 views
Software evolution understanding: Automatic extraction of software identifier... by Ra'Fat Al-Msie'deen
Software evolution understanding: Automatic extraction of software identifier...Software evolution understanding: Automatic extraction of software identifier...
Software evolution understanding: Automatic extraction of software identifier...
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium... by Lisi Hocke
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Lisi Hocke28 views
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J... by Deltares
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...
Deltares9 views
Advanced API Mocking Techniques by Dimpy Adhikary
Advanced API Mocking TechniquesAdvanced API Mocking Techniques
Advanced API Mocking Techniques
Dimpy Adhikary19 views
SUGCON ANZ Presentation V2.1 Final.pptx by Jack Spektor
SUGCON ANZ Presentation V2.1 Final.pptxSUGCON ANZ Presentation V2.1 Final.pptx
SUGCON ANZ Presentation V2.1 Final.pptx
Jack Spektor22 views
Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ... by Donato Onofri
Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ...Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ...
Unmasking the Dark Art of Vectored Exception Handling: Bypassing XDR and EDR ...
Donato Onofri795 views
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge... by Deltares
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
DSD-INT 2023 Delft3D FM Suite 2024.01 2D3D - New features + Improvements - Ge...
Deltares17 views
Fleet Management Software in India by Fleetable
Fleet Management Software in India Fleet Management Software in India
Fleet Management Software in India
Fleetable11 views

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; } };