#include <functional>
#include <iostream>
#include <type_traits>
#include <utility>
using namespace std;
template <int>
struct int_ {};
template <typename...>
struct list {};
template <typename L, typename I>
struct index;
template <typename X, typename... XS>
struct index<list<X, XS...>, int_<0>> {
typedef X type;
};
template <typename X, typename... XS, int i>
struct index<list<X, XS...>, int_<i>> {
typedef typename index<list<XS...>, int_<i-1>>::type type;
};
template <typename T>
struct remove_m_const {
typedef T type;
};
template <typename X, typename M, typename... XS>
struct remove_m_const<X (M::*)(XS...)> {
typedef X type(XS...);
};
template <typename X, typename M, typename... XS>
struct remove_m_const<X (M::*)(XS...) const> {
typedef X type(XS...);
};
template <typename T>
struct normtype {
typedef typename remove_cv<typename remove_pointer<T>::type>::type def;
typedef typename remove_m_const<typename remove_reference<def>::type>::type type;
};
template <typename T, int x>
struct argtype_impl;
template <typename T, int x>
struct argtype {
typedef typename normtype<T>::type def;
typedef typename argtype_impl<def, x>::type type;
};
template <typename T, int x>
struct argtype_impl {
typedef typename argtype<decltype(&T::operator()), x>::type type;
};
template <typename T, typename... XS, int x>
struct argtype_impl<T (XS...), x> {
typedef typename index<list<XS...>, int_<x>>::type type;
};
template <typename T>
struct rettype_impl;
template <typename T>
struct rettype {
typedef typename normtype<T>::type def;
typedef typename rettype_impl<def>::type type;
};
template <typename T>
struct rettype_impl {
typedef typename rettype<decltype(&T::operator())>::type type;
};
template <typename T, typename... XS>
struct rettype_impl<T (XS...)> {
typedef T type;
};
template <typename T, typename U>
auto compose(T a, U b) -> function<decltype(a(b(declval<typename argtype<T, 0>::type>())))(typename argtype<T, 0>::type)> {
return [a, b](typename argtype<T, 0>::type x) { return a(b(x)); };
}
template <typename F>
auto curry(F f) -> function<function<typename rettype<F>::type(typename argtype<F, 1>::type)>(typename argtype<F, 0>::type)> {
return [f](typename argtype<F, 0>::type a) { return [f, a](typename argtype<F, 1>::type b) { return f(a, b); }; };
}
int main() {
auto sum = [](int x, int y) { return x + y; };
auto mul = [](int x, int y) { return x * y; };
cout << compose(curry(mul)(2), curry(sum)(1))(20) << endl;
}
I2luY2x1ZGUgPGZ1bmN0aW9uYWw+CiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgojaW5jbHVkZSA8dXRpbGl0eT4KdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCnRlbXBsYXRlIDxpbnQ+CnN0cnVjdCBpbnRfIHt9OwoKdGVtcGxhdGUgPHR5cGVuYW1lLi4uPgpzdHJ1Y3QgbGlzdCB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBMLCB0eXBlbmFtZSBJPgpzdHJ1Y3QgaW5kZXg7CnRlbXBsYXRlIDx0eXBlbmFtZSBYLCB0eXBlbmFtZS4uLiBYUz4Kc3RydWN0IGluZGV4PGxpc3Q8WCwgWFMuLi4+LCBpbnRfPDA+PiB7CiAgICB0eXBlZGVmIFggdHlwZTsKfTsKdGVtcGxhdGUgPHR5cGVuYW1lIFgsIHR5cGVuYW1lLi4uIFhTLCBpbnQgaT4Kc3RydWN0IGluZGV4PGxpc3Q8WCwgWFMuLi4+LCBpbnRfPGk+PiB7Cgl0eXBlZGVmIHR5cGVuYW1lIGluZGV4PGxpc3Q8WFMuLi4+LCBpbnRfPGktMT4+Ojp0eXBlIHR5cGU7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4Kc3RydWN0IHJlbW92ZV9tX2NvbnN0IHsKCXR5cGVkZWYgVCB0eXBlOwp9Owp0ZW1wbGF0ZSA8dHlwZW5hbWUgWCwgdHlwZW5hbWUgTSwgdHlwZW5hbWUuLi4gWFM+CnN0cnVjdCByZW1vdmVfbV9jb25zdDxYIChNOjoqKShYUy4uLik+IHsKCXR5cGVkZWYgWCB0eXBlKFhTLi4uKTsKfTsKdGVtcGxhdGUgPHR5cGVuYW1lIFgsIHR5cGVuYW1lIE0sIHR5cGVuYW1lLi4uIFhTPgpzdHJ1Y3QgcmVtb3ZlX21fY29uc3Q8WCAoTTo6KikoWFMuLi4pIGNvbnN0PiB7Cgl0eXBlZGVmIFggdHlwZShYUy4uLik7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4Kc3RydWN0IG5vcm10eXBlIHsKCXR5cGVkZWYgdHlwZW5hbWUgcmVtb3ZlX2N2PHR5cGVuYW1lIHJlbW92ZV9wb2ludGVyPFQ+Ojp0eXBlPjo6dHlwZSBkZWY7Cgl0eXBlZGVmIHR5cGVuYW1lIHJlbW92ZV9tX2NvbnN0PHR5cGVuYW1lIHJlbW92ZV9yZWZlcmVuY2U8ZGVmPjo6dHlwZT46OnR5cGUgdHlwZTsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCBpbnQgeD4Kc3RydWN0IGFyZ3R5cGVfaW1wbDsKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIGludCB4PgpzdHJ1Y3QgYXJndHlwZSB7Cgl0eXBlZGVmIHR5cGVuYW1lIG5vcm10eXBlPFQ+Ojp0eXBlIGRlZjsKCXR5cGVkZWYgdHlwZW5hbWUgYXJndHlwZV9pbXBsPGRlZiwgeD46OnR5cGUgdHlwZTsKfTsKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIGludCB4PgpzdHJ1Y3QgYXJndHlwZV9pbXBsIHsKCXR5cGVkZWYgdHlwZW5hbWUgYXJndHlwZTxkZWNsdHlwZSgmVDo6b3BlcmF0b3IoKSksIHg+Ojp0eXBlIHR5cGU7Cn07CnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBYUywgaW50IHg+CnN0cnVjdCBhcmd0eXBlX2ltcGw8VCAoWFMuLi4pLCB4PiB7Cgl0eXBlZGVmIHR5cGVuYW1lIGluZGV4PGxpc3Q8WFMuLi4+LCBpbnRfPHg+Pjo6dHlwZSB0eXBlOwp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnN0cnVjdCByZXR0eXBlX2ltcGw7CnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpzdHJ1Y3QgcmV0dHlwZSB7Cgl0eXBlZGVmIHR5cGVuYW1lIG5vcm10eXBlPFQ+Ojp0eXBlIGRlZjsKCXR5cGVkZWYgdHlwZW5hbWUgcmV0dHlwZV9pbXBsPGRlZj46OnR5cGUgdHlwZTsKfTsKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnN0cnVjdCByZXR0eXBlX2ltcGwgewoJdHlwZWRlZiB0eXBlbmFtZSByZXR0eXBlPGRlY2x0eXBlKCZUOjpvcGVyYXRvcigpKT46OnR5cGUgdHlwZTsKfTsKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lLi4uIFhTPgpzdHJ1Y3QgcmV0dHlwZV9pbXBsPFQgKFhTLi4uKT4gewoJdHlwZWRlZiBUIHR5cGU7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgVT4KYXV0byBjb21wb3NlKFQgYSwgVSBiKSAtPiBmdW5jdGlvbjxkZWNsdHlwZShhKGIoZGVjbHZhbDx0eXBlbmFtZSBhcmd0eXBlPFQsIDA+Ojp0eXBlPigpKSkpKHR5cGVuYW1lIGFyZ3R5cGU8VCwgMD46OnR5cGUpPiB7CglyZXR1cm4gW2EsIGJdKHR5cGVuYW1lIGFyZ3R5cGU8VCwgMD46OnR5cGUgeCkgeyByZXR1cm4gYShiKHgpKTsgfTsKfQoKdGVtcGxhdGUgPHR5cGVuYW1lIEY+CmF1dG8gY3VycnkoRiBmKSAtPiBmdW5jdGlvbjxmdW5jdGlvbjx0eXBlbmFtZSByZXR0eXBlPEY+Ojp0eXBlKHR5cGVuYW1lIGFyZ3R5cGU8RiwgMT46OnR5cGUpPih0eXBlbmFtZSBhcmd0eXBlPEYsIDA+Ojp0eXBlKT4gewoJcmV0dXJuIFtmXSh0eXBlbmFtZSBhcmd0eXBlPEYsIDA+Ojp0eXBlIGEpIHsgcmV0dXJuIFtmLCBhXSh0eXBlbmFtZSBhcmd0eXBlPEYsIDE+Ojp0eXBlIGIpIHsgcmV0dXJuIGYoYSwgYik7IH07IH07Cn0KCmludCBtYWluKCkgewoJYXV0byBzdW0gPSBbXShpbnQgeCwgaW50IHkpIHsgcmV0dXJuIHggKyB5OyB9OwoJYXV0byBtdWwgPSBbXShpbnQgeCwgaW50IHkpIHsgcmV0dXJuIHggKiB5OyB9OwoJY291dCA8PCBjb21wb3NlKGN1cnJ5KG11bCkoMiksIGN1cnJ5KHN1bSkoMSkpKDIwKSA8PCBlbmRsOwp9