Funkcja „Deep” currying w C ++ za pomocą szablonowego metaprogramowania
Właśnie wymyśliłem (jeszcze jedną!) Implementację funkcji currying w C ++ za pomocą szablonowego metaprogramowania. (Jestem prawie pewien, że inne implementacje są lepsze / bardziej kompletne niż moje, ale robię to w celach edukacyjnych, w przypadku, gdy myślę, że ponowne wymyślenie koła jest uzasadnione).
Moja funkcja polegająca na wprowadzeniu curry, w tym przypadku testowego, jest następująca:
<code>#include <iostream> #include <functional> template <typename> class curry; template <typename _Res> class curry< _Res() > { public: typedef std::function< _Res() > _Fun; typedef _Res _Ret; private: _Fun _fun; public: explicit curry (_Fun fun) : _fun(fun) { } operator _Ret () { return _fun(); } }; template <typename _Res, typename _Arg, typename... _Args> class curry< _Res(_Arg, _Args...) > { public: typedef std::function< _Res(_Arg, _Args...) > _Fun; typedef curry< _Res(_Args...) > _Ret; private: class apply { private: _Fun _fun; _Arg _arg; public: apply (_Fun fun, _Arg arg) : _fun(fun), _arg(arg) { } _Res operator() (_Args... args) { return _fun(_arg, args...); } }; private: _Fun _fun; public: explicit curry (_Fun fun) : _fun(fun) { } _Ret operator() (_Arg arg) { return _Ret(apply(_fun, arg)); } }; int main () { auto plus_xy = curry<int(int,int)>(std::plus<int>()); auto plus_2x = plus_xy(2); auto plus_24 = plus_2x(4); std::cout << plus_24 << std::endl; return 0; } </code>
Ta funkcja currying implementacji jest „płytka” w następującym znaczeniu: Jeśli oryginałstd::function
podpis jest ...
<code>(arg1, arg2, arg3...) -> res </code>
Wówczas podpis funkcji kuratora to ...
<code>arg1 -> arg2 -> arg3 -> ... -> res </code>
Jednakże, jeśli którykolwiek z argumentów lub sam typ powrotu może zostać poddany curry, nie zostanie on zaklinowany. Na przykład, jeśli oryginałstd::function
podpis jest ...
<code>(((arg1, arg2) -> tmp), arg3) -> res </code>
Wtedy podpis funkcji curried będzie ...
<code>((arg1, arg2) -> tmp) -> arg3 -> res </code>
Zamiast...
<code>(arg1 -> arg2 -> tmp) -> arg3 -> res </code>
Tego właśnie chcę. Chciałbym więc mieć „głęboką” currying implementację. Czy ktoś wie, jak mogę to napisać?
@vhallac:
Jest to rodzaj funkcji, którą należy przekazać konstruktorowicurry<int(int(int,int),int)>
:
<code>int test(std::function<int(int,int)> f, int x) { return f(3, 4) * x; } </code>
Wtedy powinno być możliwe wykonanie następujących czynności:
<code>auto func_xy = curry<int(int(int,int),int)>(test); auto plus_xy = curry<int(int,int)>(std::plus<int>()); auto func_px = func_xy(plus_xy); auto func_p5 = func_px(5); std::cout << func_p5 << std::endl; </code>