Skip to content

Instantly share code, notes, and snippets.

@mattbierner
Last active January 14, 2023 17:12
Show Gist options
  • Save mattbierner/6145671 to your computer and use it in GitHub Desktop.
Save mattbierner/6145671 to your computer and use it in GitHub Desktop.
C++ std::tuple map, foldl, and foldr
/*------------------------------------------------------------------------------
Common list operations (map, foldl, foldr) for C++ tuples.
Depends on Cons, Car, and Cdr for tuples from: https://gist.github.com/mattbierner/6145505
------------------------------------------------------------------------------*/
#include "tuple_ops.h"
/* Impl --------------------- */
template<typename T, typename F>
struct MapImpl
{
static auto Map(const T& t, const F& f) -> decltype(Cons(f(Car(t)), MapImpl<decltype(Cdr(t)), F>::Map(Cdr(t), f)))
{
return Cons(f(Car(t)), MapImpl<decltype(Cdr(t)), F>::Map(Cdr(t), f));
}
};
template<typename F>
struct MapImpl<std::tuple<>, F>
{
static std::tuple<> Map(const std::tuple<>&, const F&) { return std::make_tuple(); }
};
template<typename T, typename F, typename Z>
struct FoldlImpl
{
static auto Foldl(const T& t, const F& f, Z z) ->
decltype(FoldlImpl<decltype(Cdr(t)), F, decltype(f(Car(t), z))>::Foldl(Cdr(t), f, f(Car(t), z)))
{
return FoldlImpl<decltype(Cdr(t)), F, decltype(f(Car(t), z))>::Foldl(Cdr(t), f, f(Car(t), z));
}
};
template<typename F, typename Z>
struct FoldlImpl<std::tuple<>, F, Z>
{
static Z Foldl(const std::tuple<>&, const F&, Z z) { return z; }
};
template<typename T, typename F, typename Z>
struct FoldrImpl
{
static auto Foldr(const T& t, const F& f, Z z) ->
decltype(f(Car(t), FoldrImpl<decltype(Cdr(t)), F, Z>::Foldr(Cdr(t), f, z)))
{
return f(Car(t), FoldrImpl<decltype(Cdr(t)), F, Z>::Foldr(Cdr(t), f, z));
}
};
template<typename F, typename Z>
struct FoldrImpl<std::tuple<>, F, Z>
{
static Z Foldr(const std::tuple<>&, const F& f, Z z) { return z; }
};
/* API --------------------- */
/**
* Create a new tuple from the result of applying `f` to every value in `t`.
*/
template<typename T, typename F>
auto Map(const T& t, const F& f) -> decltype(MapImpl<T, F>::Map(t, f))
{
return MapImpl<T, F>::Map(t, f);
}
/**
* Perform a left fold on tuple `t` with functor `f` and initial value `z`.
*/
template<typename T, typename F, typename Z>
auto Foldl(const T& t, const F& f, Z z) -> decltype(FoldlImpl<T, F, Z>::Foldl(t, f, z))
{
return FoldlImpl<T, F, Z>::Foldl(t, f, z);
}
/**
* Perform a right fold on tuple `t` with functor `f` and initial value `z`.
*/
template<typename T, typename F, typename Z>
auto Foldr(const T& t, const F& f, Z z) -> decltype(FoldrImpl<T, F, Z>::Foldr(t, f, z))
{
return FoldrImpl<T, F, Z>::Foldr(t, f, z);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment