Skip to content

Instantly share code, notes, and snippets.

@niha
Created June 5, 2010 13:10
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 niha/426614 to your computer and use it in GitHub Desktop.
Save niha/426614 to your computer and use it in GitHub Desktop.
// せつめい
// C++ 0x で (T1, T2, ... TN) -> R を T1 -> (T2 -> ... TN)..) -> Ret する curry を実装した。
// tuple に引数を溜めていき、最後に apply を利用して関数を呼び出す。
// decltype は再帰関数のシグネチャには使えないので返値型を計算する type function を書いた。
// enable_if で頑張れば書けそうだけれど(apply 可能かどうか)面倒なのでジェネリックには実装していない。
#include <tuple>
#include <type_traits>
#include <functional>
using namespace std;
template <unsigned int N>
struct apply_impl {
template <typename Fun, typename ...Args, typename ...BoundArgs>
static auto impl(Fun fun, tuple<Args...> t, BoundArgs... args) -> decltype(fun(declval<Args>()...)) {
return apply_impl<N-1>::impl(fun, t, std::get<N-1>(t), args...);
}
};
template <>
struct apply_impl<0> {
template <typename Fun, typename ...Args>
static auto impl(Fun fun, tuple<Args...> t, Args... args) -> decltype(fun(args...)) {
return fun(args...);
}
};
template <typename Fun, typename ...Args>
auto apply(Fun fun, tuple<Args...> t) -> decltype(fun(declval<Args>()...)) {
return apply_impl<sizeof...(Args)>::impl(fun, t);
}
template <typename Ret, typename Args>
struct RetType;
template <typename Ret>
struct RetType<Ret, tuple<>> {
typedef Ret type;
};
template <typename Ret, typename ArgsHead, typename ...ArgsTail>
struct RetType<Ret, tuple<ArgsHead, ArgsTail...>> {
typedef typename RetType<Ret, tuple<ArgsTail...>>::type Partial;
typedef function<Partial (ArgsHead)> type;
};
template <typename T>
struct curry_impl;
template <>
struct curry_impl<tuple<>> {
template <typename Ret, typename ...Args>
static auto impl(Ret (*fun)(Args...), tuple<Args...> t) -> Ret {
return apply(fun, t);
}
};
template <typename UnBoundArgsHead, typename ...UnBoundArgsTail>
struct curry_impl<tuple<UnBoundArgsHead, UnBoundArgsTail...>> {
template <typename Ret, typename ...Args, typename ...BoundArgs>
static auto impl(Ret (*fun)(Args...), tuple<BoundArgs...> t) -> typename RetType<Ret, tuple<UnBoundArgsHead, UnBoundArgsTail...>>::type {
return [fun, t](UnBoundArgsHead arg){ return curry_impl<tuple<UnBoundArgsTail...>>::impl(fun, tuple_cat(t, make_tuple(arg))); };
}
};
template <typename Ret, typename ...Args>
auto curry(Ret (*fun)(Args...)) -> typename RetType<Ret, tuple<Args...>>::type {
return curry_impl<tuple<Args...>>::impl(fun, make_tuple());
}
/////////////////////////////////////////
#include <iostream>
int f(){
return 0;
}
int g(int i){
return i;
}
int h(int i, int j){
return i + j;
}
int main(){
cout << curry(f) << endl;
cout << curry(g)(1) << endl;
cout << curry(h)(1)(2) << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment