在C ++中的函数式编程

有人可以指导我如何在C ++的function编程? 有一些很好的在线资料可以参考吗?

请注意,我知道库FC ++。 我想知道如何单独使用C ++标准库。

谢谢。

2014年8月更新:这个答案发布于2009年。C ++ 11改进了C ++函数式编程的重要性,所以这个答案不再准确。 我把它留在下面,作为历史logging。

由于这个答案卡住了接受的 – 我把它变成一个社区维基。 随意协作改进它,以现代C ++为function编程添加真实的技巧。


你不能用C ++做真正的函数式编程。 你所能做的只是大量的痛苦和复杂性(尽pipe在C ++ 11中它更容易一些)。 因此,不build议使用这种方法。 C ++支持其他编程范例相对较好,恕我直言,不应该弯曲到它支持较less的范例 – 最后它会使只有作者理解的不可读代码。

用现代的C ++可以完成令人惊讶的“函数式编程”风格。 事实上,自从“标准化”以来,这个语言一直朝着这个方向发展。

标准库包含类似于map,reduce等的algorithm(for_each,transform,adjacent_sum …)。 下一个修订版C ++ 0x包含许多function,旨在让程序员以更实用的方式(lambdaexpression式等)处理这些function。

查看各种Boost库以获得更多乐趣。 只是为了说明标准C ++包含了大量的function优点,这是标准C ++中继续传递样式的阶乘函数。

#include <iostream> // abstract base class for a continuation functor struct continuation { virtual void operator() (unsigned) const = 0; }; // accumulating continuation functor struct accum_cont: public continuation { private: unsigned accumulator_; const continuation &enclosing_; public: accum_cont(unsigned accumulator, const continuation &enclosing) : accumulator_(accumulator), enclosing_(enclosing) {}; virtual void operator() (unsigned n) const { enclosing_(accumulator_ * n); }; }; void fact_cps (unsigned n, const continuation &c) { if (n == 0) c(1); else fact_cps(n - 1, accum_cont(n, c)); } int main () { // continuation which displays its' argument when called struct disp_cont: public continuation { virtual void operator() (unsigned n) const { std::cout << n << std::endl; }; } dc; // continuation which multiplies its' argument by 2 // and displays it when called struct mult_cont: public continuation { virtual void operator() (unsigned n) const { std::cout << n * 2 << std::endl; }; } mc; fact_cps(4, dc); // prints 24 fact_cps(5, mc); // prints 240 return 0; } 

好的,我撒了一点点。 这是一个因子函子 。 毕竟,closures是一个穷人的对象,反之亦然。 C ++中使用的大多数函数技术都依赖于函子的使用(即函数对象)—你将在STL中广泛地看到这一点。

我不认为你不能在C ++中真正的,真实的函数式编程; 但它当然不是使用它的最简单或自然的方式。 此外,你可能只是使用一些function性的成语,而不是整个心态(即'stream畅的风格')

我的build议是学习一种function语言,也许从Scheme开始,然后移到Haskell。 然后使用你在C ++编程中学到的东西。 也许你不会使用明显的function风格; 但你可能会得到最大的优势(即使用不可变的结构)。

考虑我的3个研究项目:

  • C ++中的函数式和声明式devise。 ( GitHub )( 幻灯片(Rus) )( Talk(Rus) )

这个项目是“琥珀”游戏的工作原型。 代码演示了许多主要的function概念: immutabilitylambdasmonadscombinatorspure functionsdeclarative code design 。 它使用Qt C ++和C ++ 11function。

举一个简单的例子,看看如何将任务链接成一个可以修改琥珀世界的重大任务:

 const AmberTask tickOneAmberHour = [](const amber::Amber& amber) { auto action1Res = magic::anyway(inflateShadowStorms, magic::wrap(amber)); auto action2Res = magic::anyway(affectShadowStorms, action1Res); auto action3Res = magic::onFail(shadowStabilization, action2Res); auto action4Res = magic::anyway(tickWorldTime, action3Res); return action4Res.amber; }; 
  • C ++中的透镜。 ( GitHub )( 幻灯片(英文) )( Talk(Rus) )

这是C ++中genericsfunction镜头的展示。 这个实现是通过使用Variadic Templates ,一些Variadic Templates (有效的)C ++ hack来构build的,使镜头组合和整洁。 这个库只是演示的一个演示,因此它只提供一些最重要的组合器,即: set()view()traverse()bind() ,中缀文字组合toover()等。

(请注意,存在'C ++镜头' 项目 :但它不是关于真正的'镜头',这是关于C#或Java属性的getter和setter类的属性。

快速示例

 Car car1 = {"x555xx", "Ford Focus", 0, {}}; Car car2 = {"y555yy", "Toyota Corolla", 10000, {}}; std::vector<Car> cars = {car1, car2}; auto zoomer = traversed<Car>() to modelL(); std::function<std::string(std::string)> variator = [](std::string) { return std::string("BMW x6"); }; std::vector<Car> result = over(zoomer, cars, variator); QVERIFY(result.size() == 2); QVERIFY(result[0].model == "BMW x6"); QVERIFY(result[1].model == "BMW x6"); 
  • function“生活”:平行细胞自动机和连接器。 ( GitHub )( 幻灯片(英文) )( Talk(Rus) )

你可能听说过单子。 Monad现在正在谈论function性编程。 这是一个stream行语。 但是共同体呢? 我介绍了一维和二维celullar自动机与引擎盖下的共同体的概念。 目的是展示使用std :: future作为一个Par monad从单stream代码移动到并行代码是多么容易。 该项目还对两种方法进行了基准和比较。

快速示例

 template <typename A, typename B> UUB fmap( const func<B(UUA)>& f, const UUUUA& uuu) { const func<UB(UUUA)> f2 = [=](const UUUA& uuu2) { UB newUt; newUt.position = uuu2.position; newUt.field = fp::map(f, uuu2.field); return newUt; }; return { fp::map(f2, uuu.field), uuu.position }; } 

有一本叫做Functional C的书,由Pieter Hartel和Henk Muller来帮忙。 如果它仍然可用。 它的一些信息的链接在这里 。 IIRC这不是太糟糕。

可能有点晚,但对于其他人来说,我使用lua作为C ++的函数式编程扩展,这很好。 LUA