Last active
August 29, 2015 14:12
-
-
Save Garciat/5007c7a735840a234f2a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
#include <tuple> | |
#include "function_traits.cpp" | |
template <typename Func, typename Env, typename Params, typename FuncParams> | |
struct closure; | |
template <typename Func, typename... Env, typename HeadFuncParams, typename... FuncParams> | |
struct closure<Func, std::tuple<Env...>, std::tuple<>, std::tuple<HeadFuncParams, FuncParams...>> | |
: closure<Func, std::tuple<Env...>, std::tuple<HeadFuncParams>, std::tuple<FuncParams...>> | |
{ | |
using Base = closure<Func, std::tuple<Env...>, std::tuple<HeadFuncParams>, std::tuple<FuncParams...>>; | |
using Base::Base; | |
using Base::operator(); | |
}; | |
template <typename Func, typename... Env, typename HeadParams, typename... Params, typename HeadFuncParams, typename... FuncParams> | |
struct closure<Func, std::tuple<Env...>, std::tuple<HeadParams, Params...>, std::tuple<HeadFuncParams, FuncParams...>> | |
: closure<Func, std::tuple<Env...>, std::tuple<HeadParams, Params..., HeadFuncParams>, std::tuple<FuncParams...>> | |
{ | |
using Base = closure<Func, std::tuple<Env...>, std::tuple<HeadParams, Params..., HeadFuncParams>, std::tuple<FuncParams...>>; | |
using Base::Base; | |
using Base::operator(); | |
constexpr | |
auto operator()(HeadParams&& arg, Params&&... args) const& { | |
return apply(std::make_index_sequence<sizeof...(Env)>{}, std::move(arg), std::move(args)...); | |
} | |
constexpr | |
auto operator()(HeadParams&& arg, Params&&... args) && { | |
return std::move(*this).apply(std::make_index_sequence<sizeof...(Env)>{}, std::move(arg), std::move(args)...); | |
} | |
protected: | |
template <size_t... Indices> | |
constexpr | |
auto apply(std::index_sequence<Indices...>, HeadParams&& arg, Params&&... args) const& { | |
using NewEnv = std::tuple<Env..., HeadParams, Params...>; | |
using NewClosure = closure<Func, NewEnv, std::tuple<>, std::tuple<HeadFuncParams, FuncParams...>>; | |
return NewClosure{this->func, std::get<Indices>(this->env)..., std::move(arg), std::move(args)...}; | |
} | |
template <size_t... Indices> | |
constexpr | |
auto apply(std::index_sequence<Indices...>, HeadParams&& arg, Params&&... args) && { | |
using NewEnv = std::tuple<Env..., HeadParams, Params...>; | |
using NewClosure = closure<Func, NewEnv, std::tuple<>, std::tuple<HeadFuncParams, FuncParams...>>; | |
return NewClosure{std::move(this->func), std::get<Indices>(std::move(this->env))..., std::move(arg), std::move(args)...}; | |
} | |
}; | |
template <typename Func, typename... Env, typename... Params> | |
struct closure<Func, std::tuple<Env...>, std::tuple<Params...>, std::tuple<>> | |
{ | |
constexpr | |
closure(Func func, Env... args) : | |
func(std::move(func)), | |
env(std::forward<Env>(args)...) | |
{ } | |
constexpr | |
auto operator()(Params&&... args) const& { | |
return apply(std::make_index_sequence<sizeof...(Env)>{}, std::move(args)...); | |
} | |
constexpr | |
auto operator()(Params&&... args) && { | |
return std::move(*this).apply(std::make_index_sequence<sizeof...(Env)>{}, std::move(args)...); | |
} | |
protected: | |
template <size_t... Indices> | |
constexpr | |
auto apply(std::index_sequence<Indices...>, Params&&... args) const& { | |
return func(std::get<Indices>(env)..., std::move(args)...); | |
} | |
template <size_t... Indices> | |
constexpr | |
auto apply(std::index_sequence<Indices...>, Params&&... args) && { | |
return func(std::get<Indices>(std::move(env))..., std::move(args)...); | |
} | |
Func func; | |
std::tuple<Env...> env; | |
}; | |
template <typename Func> | |
auto curry(Func&& func) { | |
using Closure = closure<Func, std::tuple<>, std::tuple<>, function_arg_tuple_t<Func>>; | |
return Closure{ std::move(func) }; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment