Slide 1

Slide 1 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 1/40 Higher Order Functions in C++ compose([](const auto& s) { return s == "foo";}, std::mem_fn(&Bar::name))

Slide 2

Slide 2 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 2/40 Definition A higher-order function is a function that takes other functions as arguments or returns a function as result.

Slide 3

Slide 3 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 3/40 #include #include std::vector v; ... if (std::any_of(std::begin(v), std::end(v), [](int x) { return x == 0; })) { ... }

Slide 4

Slide 4 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 4/40 #include #include std::vector v; ... if (std::any_of(std::begin(v), std::end(v), [](int x) { return x == 0; })) { ... } template bool any_of(Iterator i, Iterator e, Predicate predicate) { while (i != e) { if (predicate(*i)) return true; i++; } return false; }

Slide 5

Slide 5 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 5/40 #include #include std::vector v; ... if (std::any_of(std::begin(v), std::end(v), [](int x) { return x == 0; })) { ... } ... int num; ... auto n = std::count_if(std::begin(v), std::end(v), [num](int x){ return x == num; });

Slide 6

Slide 6 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 6/40 [num](int x){ return x == num; }

Slide 7

Slide 7 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 7/40 auto equals(int num) { return [num](int x){ return x == num; }; }

Slide 8

Slide 8 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 8/40 template auto equals(T num) { return [num](const auto& x){ return x == num; }; }

Slide 9

Slide 9 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 9/40 template auto equals(T&& num) { return [n = std::forward(num)](const auto& x){ return x == n; }; }

Slide 10

Slide 10 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 10/40 #include #include std::vector v; ... if (std::any_of(std::begin(v), std::end(v), equals(0)) { ... } ... int num; ... auto n = std::count_if(std::begin(v), std::end(v), equals(num));

Slide 11

Slide 11 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 11/40 Live demo!

Slide 12

Slide 12 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 12/40 struct ipaddress { ipaddress(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ipaddress(uint32_t n) : num(n) {} bool operator==(ipaddress rh) const { return num == rh.num;} bool operator!=(ipaddress rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ipaddress { using ipaddress::ipaddress; }; inline ipaddress operator&(ipaddress lh, netmask rh) { return {lh.num & rh.num}; };

Slide 13

Slide 13 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 13/40 struct ipaddress { ipaddress(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ipaddress(uint32_t n) : num(n) {} bool operator==(ipaddress rh) const { return num == rh.num;} bool operator!=(ipaddress rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ipaddress { using ipaddress::ipaddress; }; inline ipaddress operator&(ipaddress lh, netmask rh) { return {lh.num & rh.num}; }; auto ip_matches(ipaddress address, netmask mask = netmask{255,255,255,255}) { return [needle = address & mask,mask](ipaddress addr) { return needle == (addr & mask); }; }

Slide 14

Slide 14 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 14/40 struct ipaddress { ipaddress(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) << 24) | (uint32_t(i2) << 16) | (uint32_t(i3) << 8) | i4) {} ipaddress(uint32_t n) : num(n) {} bool operator==(ipaddress rh) const { return num == rh.num;} bool operator!=(ipaddress rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ipaddress { using ipaddress::ipaddress; }; inline ipaddress operator&(ipaddress lh, netmask rh) { return {lh.num & rh.num}; }; auto ip_matches(ipaddress address, netmask mask = netmask{255,255,255,255}) { return [needle = address & mask,mask](ipaddress addr) { return needle == (addr & mask); }; } std::vector v; ... auto i = std::remove_if(v.begin(), v.end(), ip_matches({192,168,1,1}, {255,255,0,0));

Slide 15

Slide 15 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 15/40 class ipif { public: using state_type = enum { off, on }; ... void set_state(state_type); state_type state() { return state_; } ipaddress address() const { return addr_;} netmask mask() const { return mask_; } ipaddress gateway() const { return gw_; } private: ipaddress addr_; netmask mask_; ipaddress gw_; state_type state_; };

Slide 16

Slide 16 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 16/40 class ipif { public: using state_type = enum { off, on }; ... void set_state(state_type); state_type state() { return state_; } ipaddress address() const { return addr_; } netmask mask() const { return mask_; } ipaddress gateway() const { return gw_; } private: ipaddress addr_; netmask mask_; ipaddress gw_; state_type state_; }; To match, for example the address of an ipif, we need to make the ip_matches() predicate work on a member.

Slide 17

Slide 17 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 17/40 class ipif { public: using state_type = enum { off, on }; ... void set_state(state_type); state_type state() { return state_; } ipaddress address() const { return addr_;} netmask mask() const { return mask_; } ipaddress gateway() const { return gw_; } private: ipaddress addr_; netmask mask_; ipaddress gw_; state_type state_; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x))

Slide 18

Slide 18 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 18/40 class ipif { public: using state_type = enum { off, on }; ... void set_state(state_type); state_type state() { return state_; } ipaddress address() const { return addr_;} netmask mask() const { return mask_; } ipaddress gateway() const { return gw_; } private: ipaddress addr_; netmask mask_; ipaddress gw_; state_type state_; }; Given: f1(y) -> z ip_matches(ip) -> bool and f2(x) -> y address_of(ipif) -> ip We want a composition f(x)->z as f1(f2(x))

Slide 19

Slide 19 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 19/40 class ipif { public: using state_type = enum { off, on }; ... void set_state(state_type); state_type state() { return state_; } ipaddress address() const { return addr_;} netmask mask() const { return mask_; } ipaddress gateway() const { return gw_; } private: ipaddress addr_; netmask mask_; ipaddress gw_; state_type state_; }; template auto compose(F1 f1, F2 f2) { return [=](const auto& x) { return f1(f2(x)); }; } Given: f1(y) -> z ip_matches(ip) -> bool and f2(x) -> y address_of(ipif) -> ip We want a composition f(x)->z as f1(f2(x))

Slide 20

Slide 20 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 20/40 class ipif { public: ... ipaddress address() const { return addr_; } ... private: ipaddress addr_; ... }; std::vector interfaces; auto i = std::find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), std::mem_fn(&ipif::address));

Slide 21

Slide 21 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 21/40 class ipif { public: ... ipaddress address() const { return addr_; } ... private: ipaddress addr_; ... }; ip address_of(const ipif& interface) { return interface.address(); } std::vector interfaces; auto i = std::find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), address_of));

Slide 22

Slide 22 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 22/40 class ipif { public: ... ipaddress address() const { return addr_; } ... private: ipaddress addr_; ... }; ip address_of(const ipif& interface) { return interface.address(); } std::vector interfaces; auto i = std::find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), address_of)); auto address_of = [](const auto& obj) { return obj.address(); }

Slide 23

Slide 23 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 23/40 class ipif { public: ... ipaddress address() const { return addr_; } ... private: ipaddress addr_; ... }; auto address_matches(ip addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), address_of); } std::vector interfaces; auto i = std::find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), address_of);

Slide 24

Slide 24 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 24/40 class ipif { public: ... ipaddress address() const { return addr_; } ... private: ipaddress addr_; ... }; auto address_matches(ip addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), address_of); } std::vector interfaces; auto i = std::find_if(interfaces.begin(), interfaces.end(), address_matches({192,168,1,1}));

Slide 25

Slide 25 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 25/40 class ipif { public: using state_type = enum { off, on }; ... void set_state(state_type); state_type state() { return state_; } ipaddress address() const { return addr_; } netmask mask() const { return mask_; } ipaddress gateway() const { return gw_; } ... }; inline ip gateway_of(const ipif& interface) { return interface.gateway(); } inline ipif::state_type state_of(const ipif& interface) { return interface.state(); }

Slide 26

Slide 26 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 26/40 auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1}), state_is(ipif::off)));

Slide 27

Slide 27 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 27/40 template auto when_all(Predicates ... ps) { return [=](const auto& x) { return (ps(x) && ...); }; } auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1}), state_is(ipif::off)));

Slide 28

Slide 28 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 28/40 template auto when_all(Predicates ... ps) { return [=](const auto& x) { return (ps(x) && ...); }; } auto address_matches(ip addr, netmask mask=netmask{255,255,255,255}) { return compose(match_ip(addr, mask), address_of); } auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1}), state_is(ipif::off)));

Slide 29

Slide 29 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 29/40 template auto when_all(Predicates ... ps) { return [=](const auto& x) { return (ps(x) && ...); }; } auto address_matches(ip addr, netmask mask=netmask{255,255,255,255}) { return compose(match_ip(addr, mask), address_of); } auto state_is(ipif::state_type state) { return compose(equals(state), state_of); } auto i = find_if(v.begin(), v.end(), when_all(addr_matches({192,168,1,1}), state_is(ipif::off)));

Slide 30

Slide 30 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 30/40 for_each(v.begin(), v.end(), if_then(when_all(address_matches({192,168,1,1}, {255,255,0,0}), state_is(ipif::off)), set_state(ipif::on)));

Slide 31

Slide 31 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 31/40 template auto if_then(Predicate predicate, Action action) { return [=](auto&& x) { if (predicate(x)) { action(std::forward(x)); } }; } for_each(v.begin(), v.end(), if_then(when_all(address_matches({192,168,1,1}, {255,255,0,0}), state_is(ipif::off)), set_state(ipif::on)));

Slide 32

Slide 32 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 32/40 template auto if_then(Predicate predicate, Action action) { return [=](auto&& x) { if (predicate(x)) { action(std::forward(x)); } }; } auto set_state(ipif::state_type state) { return [=](ipif& interface) { interface.set_state(state); }; } for_each(v.begin(), v.end(), if_then(when_all(address_matches({192,168,1,1}, {255,255,0,0}), state_is(ipif::off)), set_state(ipif::on)));

Slide 33

Slide 33 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 33/40 Live demo!

Slide 34

Slide 34 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 34/40 Generic library functions ● equals(value) ... ● compose(function...) ● if_then(pred,action) ● when_all(predicate...) ● when_none(predicate...) ● when_any(predicate...) ● do_all(action...) Domain specific functions ● ip_matches(ip, mask) ● address_of(ipif) ● gateway_of(ipif) ● state_of(ipif) ● set_state(ipif&) Composed domain specific functions ● address_matches(ip) ● state_is(state_type)

Slide 35

Slide 35 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 35/40 https://github.com/rollbear/lift Generic library functions ● equals(value) ... ● compose(function...) ● if_then(pred,action) ● when_all(predicate...) ● when_none(predicate...) ● when_any(predicate...) ● do_all(action...) Domain specific functions ● ip_matches(ip, mask) ● address_of(ipif) ● gateway_of(ipif) ● state_of(ipif) ● set_state(ipif&) Composed domain specific functions ● address_matches(ip) ● state_is(state_type)

Slide 36

Slide 36 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 36/40 Take away messages ● Write functions that uses auto return type to create lambdas

Slide 37

Slide 37 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 37/40 Take away messages ● Write functions that uses auto return type to create lambdas ● Write functions that access or modify your state

Slide 38

Slide 38 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 38/40 Take away messages ● Write functions that uses auto return type to create lambdas ● Write functions that access or modify your state ● Compose functions

Slide 39

Slide 39 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 39/40 Take away messages ● Write functions that uses auto return type to create lambdas ● Write functions that access or modify your state ● Compose functions ● and write named functions that returns compositions

Slide 40

Slide 40 text

Higher Order Functions – Stockholm C++ 0x09 – Björn Fahller @bjorn_fahller 40/40 Björn Fahller https://github.com/rollbear/lift [email protected] @bjorn_fahller @rollbear cpplang, swedencpp Higher order functions in C++