用了一段时间的函数式语言像erlang、mathematica,通过fold,map,filter等高阶函数来编程确有好处。

  1. 可靠。 每个函数都只涉及其必须的变量,避免了使用指针和无关量。正所谓nocode is the best code.
  2. 简洁。 少些了一堆遍历的通用代码,确实能减少一些重复代码。
  3. 逻辑。 fold 包含了递推的逻辑。filter可以认为是取子集。因此运用高阶函数可以找到对应的数学逻辑,这样的代码更加地严谨富有逻辑。我比较推崇《算法概论》,相比《算法导论》,前者更加注重数学逻辑。一旦具备了严谨的数学逻辑,那么也就是说我们可以证明我们的代码是没有BUG的。这大概就是我们程序员的终极目标了!

当然也有它的缺点。

  1. 代码写的慢了。 经常停下来想该怎么写。
  2. 并不是所有地方都好用。 C/C++对这方面的支持比较差。

于是我写了一个扩展类,来使得STL容器具备高阶函数。 默认将结果保存到本容器。

template<class Collection>
class FP : public Collection {
public:
    template<typename T>
    FP(std::initializer_list<T> list):Collection(list) {}

    template<typename ...Args>
    explicit FP(Args... args) {
        Collection(args...);
    }

    explicit FP(Collection &c) : Collection(c) {}

    template<typename unop>
    FP<Collection> each(unop op) {
        std::for_each(this->begin(), this->end(), op);
        return *this;
    }

    template<typename unop>
    FP<Collection> map(unop op) {
        std::transform(this->begin(), this->end(), this->begin(), op);
        return *this;
    }

    template<typename unop,class ...C>
    FP<Collection> thread(unop op,C... c) {
        this->clear();
        const size_t size=get_size(c...);
        for(int i=0;i<size;i++)
            this->push_back(apply_from_tuple(op,value_tuple(i,c...)));
        return *this;
    }
    template<typename TResult, typename F>
    TResult fold(const TResult &startValue, const F &f) {
        TResult result = startValue;
        auto p = this->begin();
        while (p != this->end())
            result = f(result, *p++);
        return result;
    }

    template< typename F>
    auto reduce(const F &f) {
        auto p = this->begin();
        auto result=*p++;
        while (p != this->end())
            result = f(result,*p++ );
        return result;
    }

    template<typename binop>
    FP<Collection> zip(Collection fc, Collection sc, binop op) {
        std::transform(fc.begin(), fc.end(), sc.begin(), fc.begin(), op);
        Collection::assign(fc.begin(), fc.end());
        return *this;
    }

    template<typename Condition>
    bool exists(Condition con) {
        auto exist = std::find_if(this->begin(), this->end(), con);
        return exist != this->end();
    }


    template<typename Predicate>
    Collection filterNot(Predicate predicate) {
        auto returnIterator = std::remove_if(this->begin(), this->end(), predicate);
        this->erase(returnIterator, std::end(this));
        return *this;
    }
};

example:

int main() {
     FP<vector<int>> v1{1,2,3,4,5};
    funt(v1);
    cout<<"list : ";
    for(auto p:v1)
        cout<<" "<<p;
    cout<<endl;

    int sum=v1.reduce([](int a,int b){return a+b;});
    cout<<"sum : "<<sum<<endl;

    FP<vector<int>> v2=v1;

    cout<<"map i*i : ";
    v1.map([](int i){return i*i;}).each([](int i){
        cout<<i<<" ";
    });
    cout<<endl;


    cout<<"thread: ";
    v2.thread([](int a,int b){return a-b;},v1,v2).each([](int i){
        cout<<i<<" ";
    });
    cout<<endl;

    //对map容器操作
    FP<std::map<int,float>> m;
    for(auto i:v2)
        m[i]=i*i;
    print(m);
    m.each([](std::pair<const int,float>& it){
        it.second+=0.2;});
    cout<<"操作后"<<endl;
    print(m);

    return 0;
}

在C++中使用函数式还要考虑内存分配问题。毕竟语言支持不太好,在正式环境下还是避免使用的好。使用标准的STL transform 很大程度上也可以实现一些功能。

thread

这个操作一般的函数式语言是没有的,这个是从mathematica上学到的。它将多个大小相同的集合用函数op组合在一起,类似与ZIP操作,但zip只能处理2组容器,而thread可以处理任意个。

参考

c++函数式

本文固定链接: http://www.js-code.com/cpp/cpp_58784.html