Date post: | 28-Mar-2015 |
Category: |
Documents |
Upload: | cristobal-truman |
View: | 218 times |
Download: | 1 times |
Bartosz Milewski
I see a monad in your future
ConcurrencyFirst class functionsGeneric programmingMemory Management (move semantics)
Math nomenclatureFunctorApplicative FunctorMonadMonoid
Functional Patterns in C++
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; });
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());
Channel for passing data (John Reppy, ML)PromiseFuture
Future
Page 7
Promise
promise<string> prms; Thread A Thread B
Promise
Sharedstate
Sharedstate
Page 8
Future
promise<string> prms;auto ftr = prms.get_future();
Thread A Thread B
Future
Promise
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 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 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
ComposabilityOrthogonality (Separation of concerns)
Library Design
Problem: Apply a function to a future
future<string> ftr = async(…);…string s = ftr.get(); // blocks?… then continue to parse(s)
Then Pattern
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
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);
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
Type constructorFunction lifting: then, transform, (Haskell:
fmap)
T -> future<T>fuction<S(T)> ->
function<future<S>(future<T>));
The Functor Pattern
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
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
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
Functor pattern Type constructorFunction lifting (then, next, transform)
Collapsing (unwrap, concat)Value lifting (make_ready_future)
Monad Pattern
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
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
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
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
New patterns based on functional programmingFunctorApplicative FunctorMonadMonoid
Composability and orthogonalityResult: Library of futures
Conclusions