[misc] Functional C++ Programming

发布时间 2023-09-12 00:58:52作者: tiany7

Functional C++ Programming

Introduction

模板真是个强大的东西,能够在编译期完成很多计算,这里整了一套list编程,有点像Racket和Ocaml里面的stylish

List

这个并不难实现,我们可以通过简单的折叠表达式来实现

template <int... Values>
struct IntegerList {};

List Append

采用immutable的方式,我们可以通过递归的方式来实现append

template <typename IntegerList1, typename IntegerList2>
struct ConcatLists;

template <int... Values1, int... Values2>
struct ConcatLists<IntegerList<Values1...>, IntegerList<Values2...>> {
    using type = IntegerList<Values1..., Values2...>;
};

List Length

这个很好实现,这个其实和函数式编程差不多

首先我们去定义一个base case,当只有一个元素或者没有一个元素的时候,我们返回0和1,剩下只需要通过递归就可以完美实现了

template <int Head, int... Tail>
constexpr auto length(IntegerList<Head, Tail...>) {
    return 1 + length(IntegerList<Tail...>{});
}

template <int Head>
constexpr auto length(IntegerList<Head>) {
    return 1;
}


constexpr auto length(IntegerList<>) {
    return 0;
}

List Filter

这里我们map,filter,fold一般是需要一个lambda来进行实现,我感觉其实C++里如果后续可能的话,应该对容器在智能指针条件下进行一些拓展支持,像Rust一样可以在runtime进行链式调用,现在stl function里的东西更像是C那一套而不是真正的OOP

这个的实现其实要注意一点,msys在新版本如果是空的内容,就不用用template <>了,直接不用template就可以了,否则会报错

template <int Head, int... Tail, typename Predicate>
constexpr auto filter(IntegerList<Head, Tail...>, Predicate pred) {
    if constexpr (pred(Head)) {
        return typename ConcatLists<IntegerList<Head>, decltype(filter(IntegerList<Tail...>{}, pred))>::type{};
    } else {
        return filter(IntegerList<Tail...>{}, pred);
    }
}

// 基本情况:当整数列表为空时停止递归
template <typename Predicate>
constexpr auto filter(IntegerList<>, Predicate pred) {
    return IntegerList<>{};
}

List Fold

template <int... Values, typename Func>
constexpr auto fold(IntegerList<Values...>, Func func) {
    return (func(Values), ...);
}

List Map

为了避免命名冲突,我用了filter_map当作名称,但是实际上这不是option,所以不应该叫filter_map,应该叫map

template <int... Values, typename Func>
constexpr auto filter_map(IntegerList<Values...>, Func func) {
    return IntegerList<func(Values)...>{};
}

List Reverse

很简单,和concat反着来就好了

template <typename CurrentList>
constexpr auto reverse(CurrentList currentList) {
    return currentList;
}

template <int Head, int... Tail>
constexpr auto reverse(IntegerList<Head, Tail...>) {
    return typename ConcatLists<decltype(reverse(IntegerList<Tail...>{})), IntegerList<Head>>::type{};
}

sum up

归根结底其实并不难,我们首先定义规则,然后拆包就好了。关键是这套规则还不太熟悉,希望赶紧熟悉一下