有人可以指导我如何在C++中进行函数式编程吗?是否有一些好的在线材料可以供我参考?
请注意,我知道FC++库。我想知道如何仅使用C++标准库来完成。
谢谢。
有人可以指导我如何在C++中进行函数式编程吗?是否有一些好的在线材料可以供我参考?
请注意,我知道FC++库。我想知道如何仅使用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;
}
好吧,我说了一点谎,它是一个阶乘函数对象。毕竟,闭包是穷人的对象...反之亦然。C++中使用的大多数函数式技术都依赖于使用函数对象(即函数对象)---您将在STL中广泛看到这一点。
std::function
,std::bind
和std::ref
。结合起来,您可以获得“函数作为参数”。再加上#include <algorithm>
以及编写没有副作用的函数,您就可以进行函数式编程了。 - Charles L Wilcox更新于 2014 年 8 月:此回答发布于 2009 年。C++11 在 C++ 函数式编程方面有了相当的改进,因此本回答已不再准确。我将其保留在下方作为历史记录。
由于此回答被选中为最佳答案,我将其转换为社区 Wiki。欢迎协作改进,以添加关于现代 C++ 中函数式编程的实际提示。
你不能真正使用 C++ 进行函数式编程,你只能通过大量的痛苦和复杂性来近似实现它(虽然在 C++11 中这变得稍微容易了一些)。因此,不建议采用这种方法。C++ 相对较好地支持其他编程范例,并且在我看来,不应弯曲其支持较差的范例 - 最终将使只有作者理解的代码难以阅读。
更新于2018年12月
我已经创建了一个全面的材料列表,您可以在其中找到文章、讲座、屏幕录像、论文、库和展示:
考虑我的四个研究项目:
该项目是“Amber”游戏的工作原型。 代码演示了许多主要的功能概念:不可变性
,lambda表达式
,monad
,组合子
,纯函数
,声明式代码设计
。它使用Qt C ++和C ++ 11功能。
例如,可以看到如何将任务链接成一个大任务,当应用时会修改Amber的世界:
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++中通用函数lenses的示例。使用了Variadic Templates
,一些有趣(且有效)的C++技巧来使lenses可以组合并且看起来简洁。该库仅为演示目的,因此仅提供了一些最重要的组合器,即:set()
、view()
、traverse()
、bind()
、中缀字面量组合器to
、over()
等。
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");
你可能听说过单子(monads)。如今在函数编程的谈话中无处不在地都能听到单子这个词。但是什么是共单子(comonads)呢?我介绍了带有共单子概念的一维和二维细胞自动机。目的是展示如何轻松地使用 std::future 作为 Par monad 从单流代码转移到并行代码。该项目还对两种方法进行了基准测试和比较。
快速示例
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 };
}
这个库基于自由单子(Free monad)
和其他一些函数式编程的高级思想。其接口类似于Haskell的本地STM库。事务可以在单子中组合,是纯函数式的,还有很多有用的单子组合器,使设计并发模型更加方便和强大。我使用这个库实现了哲学家就餐问题(Dining Philosophers problem),并且它运行良好。这是一些哲学家取叉子的交易示例:
STML<Unit> takeFork(const TFork& tFork) {
return withTVar<Fork, Unit>(tFork, [=](const Fork& fork) {
if (fork.state == ForkState::Free) {
return writeTVar<Fork>(tFork, Fork {fork.name, ForkState:Taken});
}
else {
return retry<Unit>();
}
});
}
STML<Unit> takeForks(const TForkPair& forks) {
STML<Unit> lm = takeFork(forks.left);
STML<Unit> rm = takeFork(forks.right);
return sequence(lm, rm);
}
可能有点晚了,但对于其他寻找答案的人 - 我使用Lua作为C ++的函数式编程扩展,它非常棒。 lua