1 / 26

I see a monad in your future

I see a monad in your future. Bartosz Milewski. Functional Patterns in C++. Concurrency First class functions Generic programming Memory Management (move semantics) Math nomenclature Functor Applicative Functor Monad Monoid. Higher Order Functions. Sorting: compare function

idalee
Download Presentation

I see a monad in your future

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. I see a monad in your future Bartosz Milewski

  2. Functional Patterns in C++ • Concurrency • First class functions • Generic programming • Memory Management (move semantics) • Math nomenclature • Functor • Applicative Functor • Monad • Monoid

  3. Higher Order Functions • Sorting: compare function • Find, copy_if: predicate function • Accumulate: binary function for_each(v.begin(), v.end(), [](char c) { cout << c; }); transform(v.begin(), v.end(), w.begin(), [](int x) { return x * x; });

  4. Combinators • Currying, partial application: bind • Combining algorithms v.erase(remove_if(v.begin(), v.end(), bind(logical_and<bool>(), bind(greater<int>(), _1, -10), bind(less<int>(), _1, 10))), v.end());

  5. Future • Channel for passing data (John Reppy, ML) • Promise • Future

  6. Promise promise<string> prms; Thread A Thread B Promise Shared state Page 7

  7. Future promise<string> prms; auto ftr = prms.get_future(); Thread A Thread B Future Promise Shared state Page 8

  8. Create thread promise<string> prms; auto ftr = prms.get_future(); thread th(&thFun, std::move(prms)); Thread A Thread B Future Promise Shared state Page 9

  9. set_value promise<string> prms; auto ftr = prms.get_future(); thread th(&thFun, std::move(prms)); Thread A Thread B Future Promise Thread B Shared state prms.set_value(“Hello from future”); Hello Page 10

  10. get promise<string> prms; auto ftr = prms.get_future(); thread th(&thFun, std::move(prms)); std::string str = ftr.get(); Thread A Thread B Future Promise Thread B Shared state prms.set_value(“Hello from future”); Hello Page 11

  11. Library Design • Composability • Orthogonality (Separation of concerns)

  12. Then Pattern • Problem: Apply a function to a future • future<string> ftr = async(…); • … • string s = ftr.get(); // blocks? • … then continue to parse(s)

  13. Then Combinator • future<string> ftr = async(…); • string s = ftr.get(); // blocks? • … then parse(s) 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? • Next combinator future<Tree> fTree = ftr.next(parse); Tree tree = fTree.get(); // blocks?

  14. Function Lifting • next “lifts” parse to act on futures future<string> fStr = … future<Tree> fTree = fStr.next(parse); vector<int> v = {1, 2, 3}; vector<int> w; w.resize(v.size()); transform(v.begin(), v.end(), w.begin(), square); • transform “lifts” square to act on containers

  15. Type Constructor • 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>

  16. The Functor Pattern • Type constructor • Function lifting: then, transform, (Haskell: fmap) • T -> future<T> • fuction<S(T)> -> function<future<S>(future<T>));

  17. Asynchronous Chaining • 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);

  18. Unwrap • Collapse two levels of future • async_open("foo.cpp").next(&async_read).unwrap().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

  19. Lifting a value • Usage: conditional asynchrony, recursion • A future that is ready • make_ready_future • future<int> fint = make_ready_future<int>(42); • inti = fint.get(); // doesn’t block • Analogously, for containers: • vector<int> v = {42};

  20. Monad Pattern • Functor pattern • Type constructor • Function lifting (then, next, transform) • Collapsing (unwrap, concat) • Value lifting (make_ready_future)

  21. Monad Pattern 2 • Type constructor • Value 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

  22. Exceptions • It’s all in the wrist • next (or bind) checks for exceptions and propagates them (without calling the continuation) • At the end of the chain, recover from exception • async_open("foo.cpp").next(&async_read).next(parse).recover(&on_error); • Exception monad • Implements short-circuiting • Can be put on top of the future monad (monad transformers)

  23. Applicative Pattern • Problem: Need N futures to proceed. • Create a barrier, get all values, proceed. • when_all: takes futures, returns future of finished futures • Client gets, iterates, gets each, and proceeds with values • Functional approach • Apply a regular function of n argument to n futures. • Lifting of n-ary functions • when_all_done(futures).next(fn) • Together with make_ready_future: applicative functor

  24. Monoid Pattern • Problem: Wait for the first future to complete • when_any: takes futures, returns a future of futures, at least one of them ready • Client gets, iterates, checks is_ready, picks value. proceeds • Functional approach • The OR combinator (like addition?) • Combines two futures into one • Assoc.: (f1 OR f2) OR f3 = f1 OR (f2 OR f3) • Neutral element: the “never” future • never OR f = f = f OR never • Defines a monoid

  25. Conclusions • New patterns based on functional programming • Functor • Applicative Functor • Monad • Monoid • Composabilityand orthogonality • Result: Library of futures

More Related