26

Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Embed Size (px)

Citation preview

Page 1: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor
Page 2: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Bartosz Milewski

I see a monad in your future

Page 3: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

ConcurrencyFirst class functionsGeneric programmingMemory Management (move semantics)

Math nomenclatureFunctorApplicative FunctorMonadMonoid

Functional Patterns in C++

Page 4: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Sorting: compare functionFind, copy_if: predicate functionAccumulate: binary function

Higher Order Functions

for_each(v.begin(), v.end(), [](char c) { cout << c; });

transform(v.begin(), v.end(), w.begin(), [](int x) { return x * x; });

Page 5: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Currying, partial application: bindCombining algorithms

Combinators

v.erase(remove_if(v.begin(), v.end(), bind(logical_and<bool>(), bind(greater<int>(), _1, -10), bind(less<int>(), _1, 10))), v.end());

Page 6: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Channel for passing data (John Reppy, ML)PromiseFuture

Future

Page 7: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Page 7

Promise

promise<string> prms; Thread A Thread B

Promise

Sharedstate

Page 8: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Sharedstate

Page 8

Future

promise<string> prms;auto ftr = prms.get_future();

Thread A Thread B

Future

Promise

Page 9: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Page 9

Create thread

promise<string> prms;auto ftr = prms.get_future();thread th(&thFun, std::move(prms));

Thread A Thread B

Sharedstate

Future

Promise

Page 10: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Page 10set_value

promise<string> prms;auto ftr = prms.get_future();thread th(&thFun, std::move(prms));

Thread A Thread B

Sharedstate

Future

Promise

prms.set_value(“Hello from future”);

Hello

Thread B

Page 11: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Page 11get

promise<string> prms;auto ftr = prms.get_future();thread th(&thFun, std::move(prms));std::string str = ftr.get();

Thread A Thread B

Sharedstate

Future

Promise

prms.set_value(“Hello from future”);

Hello

Thread B

Page 12: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

ComposabilityOrthogonality (Separation of concerns)

Library Design

Page 13: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Problem: Apply a function to a future

future<string> ftr = async(…);…string s = ftr.get(); // blocks?… then continue to parse(s)

Then Pattern

Page 14: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

future<string> ftr = async(…);string s = ftr.get(); // blocks?… then parse(s)

Then Combinator

template<typename F> auto future::then(F&& func) -> future<decltype(func(*this))>;future<Tree> fTree = ftr.then([](future<string> fstr) { return parse(fstr.get()); // doesn’t block});Tree tree = fTree.get(); // blocks?

future<Tree> fTree = ftr.next(parse);Tree tree = fTree.get(); // blocks?

Next combinator

Page 15: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

next “lifts” parse to act on futures

Function Liftingfuture<string> fStr = …future<Tree> fTree = fStr.next(parse);

» transform “lifts” square to act on containers

vector<int> v = {1, 2, 3};vector<int> w;w.resize(v.size());transform(v.begin(), v.end(), w.begin(), square);

Page 16: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Unconstrained parametric polymorphism (universally quantified types)

For all types T:template<class T> class future;template<class T> class vector;template<class T> class unique_ptr;

A mapping of types:T -> future<T>

Type Constructor

Page 17: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Type constructorFunction lifting: then, transform, (Haskell:

fmap)

T -> future<T>fuction<S(T)> ->

function<future<S>(future<T>));

The Functor Pattern

Page 18: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Problem: Composing (chaining) async calls

future<HANDLE> async_open(string &);future<Buffer> async_read(HANDLE fh);In principle, this is the result:future<future<Buffer>> ffBuf =

async_open("foo").next(&async_read);

Asynchronous Chaining

Page 19: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Collapse two levels of futureasync_open("foo.cpp").next(&async_read).un

wrap().next(&async_process).unwrap();

Combination of next and unwrap called bind(Haskell: >>=, bind combines join with

fmap)In C++, next (then) can be overloaded to

serve as bind

Unwrap

Page 20: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Usage: conditional asynchrony, recursion

A future that is readymake_ready_future

future<int> fint = make_ready_future<int>(42);int i = fint.get(); // doesn’t block

Analogously, for containers:vector<int> v = {42};

Lifting a value

Page 21: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Functor pattern Type constructorFunction lifting (then, next, transform)

Collapsing (unwrap, concat)Value lifting (make_ready_future)

Monad Pattern

Page 22: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Type constructorValue lifting: make_ready_future()bind: combination of .next(f).unwrap() [or an

overload of next]

Usage of the future monad pattern: Composing libraries of async functions

Monad Pattern 2

Page 23: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

It’s all in the wristnext (or bind) checks for exceptions and

propagates them (without calling the continuation)

At the end of the chain, recover from exceptionasync_open("foo.cpp").next(&async_read).next(

parse).recover(&on_error);Exception monad

Implements short-circuitingCan be put on top of the future monad (monad

transformers)

Exceptions

Page 24: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Problem: Need N futures to proceed.Create a barrier, get all values, proceed.when_all: takes futures, returns future of

finished futuresClient gets, iterates, gets each, and proceeds

with valuesFunctional approach

Apply a regular function of n argument to n futures.

Lifting of n-ary functionswhen_all_done(futures).next(fn)Together with make_ready_future: applicative

functor

Applicative Pattern

Page 25: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

Problem: Wait for the first future to completewhen_any: takes futures, returns a future of

futures, at least one of them readyClient gets, iterates, checks is_ready, picks

value. proceedsFunctional approach

The OR combinator (like addition?)Combines two futures into oneAssoc.: (f1 OR f2) OR f3 = f1 OR (f2 OR f3)Neutral element: the “never” futurenever OR f = f = f OR neverDefines a monoid

Monoid Pattern

Page 26: Bartosz Milewski Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor

New patterns based on functional programmingFunctorApplicative FunctorMonadMonoid

Composability and orthogonalityResult: Library of futures

Conclusions