Skip to content

Instantly share code, notes, and snippets.

@Garciat
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Garciat/5007c7a735840a234f2a to your computer and use it in GitHub Desktop.
Save Garciat/5007c7a735840a234f2a to your computer and use it in GitHub Desktop.
#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