Compound Light Microscope Has two lenses Light must pass through object to be seen.
Functional microscope - Lenses in C++
-
Upload
alexander-granin -
Category
Software
-
view
682 -
download
0
Transcript of Functional microscope - Lenses in C++
![Page 2: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/2.jpg)
Me?
● C++, Haskell, C#
● C++ User Group Novosibirsk, 2014
● Talks, articles, FP evangelism...
● LambdaNsk - Novosibirsk FP-community
● Kaspersky Lab
![Page 3: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/3.jpg)
struct Presentation{
FP in C++?..Functional Lensescpp_lenses library
};
![Page 4: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/4.jpg)
4
FP in C++?..
![Page 5: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/5.jpg)
С++ User Group Novosibirsk, 2014
![Page 6: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/6.jpg)
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
![Page 7: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/7.jpg)
7
Functional Lenses
Lens 2 Lens 3Lens 1
![Page 8: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/8.jpg)
8
Matryoshka
struct Account { Person person; };
struct Person { Address address; };
struct Address{ std::string street; int house; int flat;};
![Page 9: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/9.jpg)
9
Mutable variables...void setStreet(Account& account, const std::string& newStreet){ account.person.address.street = newStreet;}
![Page 10: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/10.jpg)
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
![Page 11: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/11.jpg)
11
Mutable state...void Account::setStreet(const std::string& newStreet) { this->person.address.street = newStreet;}
![Page 12: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/12.jpg)
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
![Page 13: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/13.jpg)
13
Account setStreet(Account account, const std::string& newStreet){ account.person.address.street = newStreet; return account;}
Immutable approach…
![Page 14: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/14.jpg)
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
![Page 15: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/15.jpg)
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
![Page 16: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/16.jpg)
Ok, Lenses!
auto lens = zoom(personLens, addressLens, streetLens);
auto newAccount = set(lens, oldAccount, std::string("New street"));
So, how does this work?
![Page 17: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/17.jpg)
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);
![Page 18: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/18.jpg)
Person getPerson(const Account& account) { return account.person;}
Account setPerson(Account account, const Person& person) { account.person = person; return account;}
getA(), setA()
![Page 19: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/19.jpg)
auto getPerson = [](const Account& account) { return account.person;};
auto setPerson = [](Account account, const Person& person) { account.person = person; return account;};
Getter, Setter
![Page 20: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/20.jpg)
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;
![Page 21: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/21.jpg)
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
![Page 22: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/22.jpg)
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);
![Page 23: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/23.jpg)
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”));
![Page 24: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/24.jpg)
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”));
![Page 25: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/25.jpg)
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, setPersonAccount newAccount = set(lens, someAccount, std::string(”Churchill's”));
![Page 26: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/26.jpg)
26
cpp_lens library
![Page 27: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/27.jpg)
Manual lensestemplate <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; });
![Page 28: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/28.jpg)
Autolensesstruct 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()
![Page 29: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/29.jpg)
zoomLens<A, B> lens = aToB;???<A, B, C> lens = zoom(aToB, bToC);???<A, B, C, D> lens = zoom(aToB, bToC, cToD);
![Page 30: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/30.jpg)
zoom (not generic) -> LensStackLens<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(...) { ... }
![Page 31: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/31.jpg)
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); // OKLensStack<A, B, C, D> lens = zoom(aToB, bToC, cToD); // OK
LensStack<A, B, C, D, E> lens = zoom(aToB, bToC, cToD, dToE); // Ooops!
![Page 32: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/32.jpg)
LensStack: Variadic Templates + magictemplate<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;};
![Page 33: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/33.jpg)
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-associativeauto lens = a to (b to c); // Error
![Page 34: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/34.jpg)
`to`: proxy + overloading + reroll stackstruct 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 >
![Page 35: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/35.jpg)
set
auto lens = personL() to addressL() to houseL();
Account account1 = {...};Account account2 = set(lens, account1, 20); // house == 20
![Page 36: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/36.jpg)
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
![Page 37: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/37.jpg)
What about containers?struct Car { std::string model; };
std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} };
![Page 38: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/38.jpg)
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...
![Page 39: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/39.jpg)
traversedstruct Account { Person person; };struct Person { std::vector<Car> cars; };struct Car { std::string model; int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
![Page 40: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/40.jpg)
traversed + setstruct 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”));
![Page 41: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/41.jpg)
traversed + overstruct 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);
![Page 42: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/42.jpg)
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>();
![Page 43: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/43.jpg)
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
![Page 44: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/44.jpg)
● 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++?
![Page 46: Functional microscope - Lenses in C++](https://reader031.fdocuments.us/reader031/viewer/2022021814/58ed86c81a28aba2118b45b9/html5/thumbnails/46.jpg)
Rerolling LensStacktemplate<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 basetemplate <typename... Tail>struct LensStack{ template <typename Reroll, typename Lx> void reroll_(Reroll& rerolled, const Lx& lx) { rerolled.m_lens = lx; }};