用了一段时间的函数式语言像erlang、mathematica,通过fold,map,filter
等高阶函数来编程确有好处。
- 可靠。 每个函数都只涉及其必须的变量,避免了使用指针和无关量。正所谓nocode is the best code.
- 简洁。 少些了一堆遍历的通用代码,确实能减少一些重复代码。
- 逻辑。 fold 包含了递推的逻辑。filter可以认为是取子集。因此运用高阶函数可以找到对应的数学逻辑,这样的代码更加地严谨富有逻辑。我比较推崇《算法概论》,相比《算法导论》,前者更加注重数学逻辑。一旦具备了严谨的数学逻辑,那么也就是说我们可以证明我们的代码是没有BUG的。这大概就是我们程序员的终极目标了!
当然也有它的缺点。
- 代码写的慢了。 经常停下来想该怎么写。
- 并不是所有地方都好用。 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可以处理任意个。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。