在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概念: immutability
, lambdas
, monads
, combinators
, pure functions
, declarative 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()
,中缀文字组合to
, over()
等。
(请注意,存在'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