Red*_*ena 52 c++ functional-programming
有人可以指导我如何在C++中进行函数式编程吗?我可以参考哪些好的在线资料?
请注意,我知道库FC++.我想知道如何单独使用C++标准库.
谢谢.
Der*_*urk 47
您可以使用现代C++实现惊人数量的"函数式编程"风格.事实上,自从标准化以来,语言一直在朝这个方向发展.
标准库包含类似于map,reduce等的算法(for_each,transform,adjacent_sum ...).下一个版本C++ 0x包含许多功能,旨在让程序员以更实用的方式(lambda表达式等)使用它们.
查看各种Boost库以获得更多乐趣.为了说明标准C++包含大量的功能优点,这里是标准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;
}
Run Code Online (Sandbox Code Playgroud)
好吧,我撒谎了一下.这是一个因子函子.毕竟,闭包是一个穷人的对象......反之亦然.C++中使用的大多数功能技术都依赖于函子(即函数对象)的使用---你会在STL中广泛地看到它.
Eli*_*sky 24
2014年8月更新:这个答案发布于2009年.C++ 11改进了C++中函数式编程的重要性,因此这个答案不再准确.我将它留在下面以获得历史记录.
由于这个答案被认为是被接受的答案 - 我将其转变为社区Wiki.随意协作改进它以添加有关现代C++的函数编程的真实技巧.
你不能用C++ 进行真正的函数式编程.所有你能做的就是用大量的痛苦和复杂性来近似它(尽管在C++ 11中它更容易一些).因此,不建议采用这种方法.C++相对较好地支持其他编程范例,并且IMHO不应该倾向于它支持不太好的范例 - 最终它将使得只有作者理解的不可读代码.
gra*_*nas 11
UPD 2018年12月
我已经创建了一个完整的材料列表,您可以在其中找到文章,讲座,截屏视频,论文,图书馆和展示:
考虑我的4个研究项目:
这个项目是'Amber'游戏的工作原型.代码演示了许多的主要功能概念:immutability
,lambdas
,monads
,combinators
,pure functions
,declarative code design
.它使用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;
};
Run Code Online (Sandbox Code Playgroud)
这是C++中通用功能镜头的展示.这个实现是利用Variadic Templates
一些有趣的(和有效的)C++黑客来构建,使镜头可以组合和整洁.图书馆是只是为了通话演示,因此它仅提供了几个最重要的组合子,即:set()
,view()
,traverse()
,bind()
,缀文字组合子to
,over()
等.
(请注意,存在'C++ Lenses' 项目:但它不是关于真正的'镜头',而是关于具有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");
Run Code Online (Sandbox Code Playgroud)
你可能听说过monads.Monads现在到处都在讨论函数式编程.这是一个流行语.但是comonads怎么样?我提出了1D和2D celullar自动机与引擎盖下的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 };
}
Run Code Online (Sandbox Code Playgroud)
Software Transactional Memory (STM)
被称为纯函数库cpp_stm_free
.(GitHub)(幻灯片(Eng))(谈话(Rus))(教程(Eng))(餐饮哲学家样本).该库基于Free monad
功能编程的一些其他高级思想.它的界面类似于Haskell的原生STM库.事务是可单一组合的,纯函数式的,并且有许多有用的monadic组合器可以使并发模型的设计更加方便和强大.我使用图书馆实现了餐饮哲学家的问题,而且效果很好.以下是哲学家采取分叉的一些交易样本:
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);
}
Run Code Online (Sandbox Code Playgroud)
我不认为你不能用C++进行真正的,真实的函数式编程; 但它肯定不是使用它的最简单或最自然的方式.此外,你可能只是使用一些功能性的习语,而不是整个心态(即'流畅的风格')
我的建议是学习一种函数式语言,可能从Scheme开始,然后转到Haskell.然后使用您在C++中编程时学到的知识.也许你不会使用明显的功能风格; 但是你可能会获得最大的优势(即使用不可变结构).
归档时间: |
|
查看次数: |
19766 次 |
最近记录: |