Skip to content

Instantly share code, notes, and snippets.

@Y-Less
Created November 13, 2019 11:25
Show Gist options
  • Save Y-Less/decb4cd503b3eb5de1f9992ce82d7b66 to your computer and use it in GitHub Desktop.
Save Y-Less/decb4cd503b3eb5de1f9992ce82d7b66 to your computer and use it in GitHub Desktop.
Curry functions. Can be improved with better move semantics.
#include <tuple>
#include <functional>
template <typename RET, typename FUNC, int N, typename... ARGS>
struct CurriedCaller
{
template <typename... TUPLED>
static RET Call(FUNC & f, std::tuple<TUPLED...> const & t, ARGS ...args)
{
return CurriedCaller<RET, FUNC, N - 1, decltype (std::get<N - 1>(t)), ARGS...>::Call(f, t, std::get<N - 1>(t), args...);
}
};
template <typename RET, typename FUNC, typename... ARGS>
struct CurriedCaller<RET, FUNC, 0, ARGS...>
{
template <typename... TUPLED>
static RET Call(FUNC & f, std::tuple<TUPLED...> const &, ARGS ...args)
{
return f(args...);
}
};
template <typename RET, typename FUNC, typename TUPLE, typename... ARGS>
class CurriedContainer
{
public:
CurriedContainer(FUNC & func, TUPLE && saved)
:
func_(func),
saved_(std::move(saved))
{
}
RET operator()()
{
return CurriedCaller<std::tuple_size<TUPLE>()>::Call(func_, saved_);
}
private:
TUPLE
saved_;
FUNC
func_;
};
template <typename RET, typename FUNC, typename TUPLE, typename A, typename... ARGS>
class CurriedContainer<RET, FUNC, TUPLE, A, ARGS...>
{
public:
CurriedContainer(FUNC func, TUPLE && saved)
:
func_(std::move(func)),
saved_(std::move(saved))
{
}
RET operator()(A one)
{
return CurriedCaller<RET, FUNC, std::tuple_size<TUPLE>::value, A>::Call(func_, saved_, one);
}
private:
TUPLE
saved_;
FUNC
func_;
};
template <typename RET, typename FUNC, typename TUPLE, typename A, typename B, typename... ARGS>
class CurriedContainer<RET, FUNC, TUPLE, A, B, ARGS...>
{
public:
CurriedContainer(FUNC func, TUPLE && saved)
:
func_(std::move(func)),
saved_(std::move(saved))
{
}
auto operator()(A param)
{
return CurriedContainer<RET, FUNC, decltype (std::tuple_cat(saved_, std::make_tuple(param))), B, ARGS...>(func_, std::tuple_cat(saved_, std::make_tuple(param)));
}
RET operator()(A one, B two, ARGS... rest)
{
return CurriedCaller<RET, FUNC, std::tuple_size<TUPLE>::value, A, B, ARGS...>::Call(func_, saved_, one, two, rest...);
}
private:
TUPLE
saved_;
FUNC
func_;
};
template <typename RET, typename... ARGS>
auto Curry(std::function<RET(ARGS...)> & func)
{
return CurriedContainer<RET, std::function<RET(ARGS...)>, std::tuple<>, ARGS...>(func, std::make_tuple());
}
template <typename RET, typename... ARGS>
auto Curry(RET (*func)(ARGS...))
{
return CurriedContainer<RET, std::function<RET(ARGS...)>, std::tuple<>, ARGS...>(std::function<RET(ARGS...)>(func), std::make_tuple());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment