C++ 函数式编程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1981400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Functional Programming in C++
提问by Red Hyena
Can someone guide me how do functional programming in C++? Is there some good online material that I can refer?
有人可以指导我如何在 C++ 中进行函数式编程吗?有什么好的在线资料可以参考吗?
Please note that I know about the library FC++. I want to know how to do that with C++ standard library alone.
请注意,我了解 FC++ 库。我想知道如何单独使用 C++ 标准库来做到这一点。
Thanks.
谢谢。
采纳答案by Eli Bendersky
Update August 2014: This answer was posted in 2009. C++11 improved matters considerably for functional programming in C++, so this answer is no longer accurate. I'm leaving it below for a historical record.
2014 年 8 月更新:此答案于 2009 年发布。C++11 显着改善了 C++ 中函数式编程的问题,因此此答案不再准确。我把它留在下面作为历史记录。
Since this answer stuck as the accepted one - I'm turning it into a community Wiki. Feel free to collaboratively improve it to add real tips on function programming with modern C++.
由于这个答案一直被接受 - 我将它变成了一个社区 Wiki。随意协作改进它以添加有关使用现代 C++ 进行函数编程的真正技巧。
You can not do truefunctional programming with C++. All you can do is approximate it with a large amount of pain and complexity (although in C++11 it's a bit easier). Therefore, this approach isn't recommended. C++ supports other programming paradigms relatively well, and IMHO should not be bent to paradigms it supports less well - in the end it will make unreadable code only the author understands.
你不能用 C++进行真正的函数式编程。你所能做的就是用大量的痛苦和复杂性来近似它(尽管在 C++11 中它更容易一些)。因此,不推荐这种方法。C++ 对其他编程范式的支持相对较好,恕我直言,不应该屈服于它支持的不太好的范式——最终它会产生只有作者理解的不可读代码。
回答by Derrick Turk
You can accomplish a surprising amount of "functional programming" style with modern C++. In fact, the language has been trending in that direction since its' standardization.
您可以使用现代 C++ 完成数量惊人的“函数式编程”风格。事实上,自标准化以来,该语言一直在朝着这个方向发展。
The standard library contains algorithms analogous to map, reduce, etc (for_each, transform, adjacent_sum...). The next revision, C++0x, contains many features designed to let programmers work with these in a more functional style (lambda expressions, etc.).
标准库包含类似于 map、reduce 等的算法(for_each、transform、neighbor_sum...)。下一个修订版 C++0x 包含许多旨在让程序员以更具功能性的风格(lambda 表达式等)使用这些功能的功能。
Look into the various Boost libraries for more fun. Just to illustrate that standard C++ contains plenty of functional goodness, here's a factorial function in continuation-passing style in standard C++.
查看各种 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;
}
Ok, I lied a little bit. It's a factorial functor. After all, closures are a poor man's objects... and vice versa. Most of the functional techniques used in C++ rely on the use of functors (i.e. function objects)---you'll see this extensively in the STL.
好吧,我撒了一点谎。这是一个阶乘函子。毕竟,闭包是穷人的对象……反之亦然。C++ 中使用的大多数函数式技术都依赖于函子(即函数对象)的使用——您将在 STL 中广泛地看到这一点。
回答by graninas
UPD Dec 2018
UPD 2018 年 12 月
I've created a comprehensive list of materials where you can find articles, talks, screencasts, papers, libraries and showcases:
我创建了一个完整的材料列表,您可以在其中找到文章、演讲、截屏视频、论文、图书馆和展示:
Consider my 4 research projects:
考虑我的 4 个研究项目:
- Functional and Declarative Design in C++. (GitHub) (Slides (Rus)) (Talk (Rus))
- C++ 中的函数式和声明式设计。( GitHub) ( Slides (Rus)) ( Talk (Rus))
This project is a working prototype of 'Amber' game. The code demonstrates many of major functional concepts: immutability
, lambdas
, monads
, combinators
, pure functions
, declarative code design
. It uses Qt C++ and C++11 features.
该项目是“琥珀”游戏的工作原型。该代码演示了许多主要的功能概念:immutability
、lambdas
、monads
、combinators
、pure functions
、declarative code design
。它使用 Qt C++ 和 C++11 特性。
For a quick example, see how tasks can be chained into one big task that will modify the Amber's world when it's applied:
举个简单的例子,看看如何将任务链接成一个大任务,当它被应用时,它将修改琥珀的世界:
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;
};
- Lenses in C++. (GitHub) (Slides (Eng)) (Talk (Rus))
- C++ 中的镜头。( GitHub) ( Slides (Eng)) ( Talk (Rus))
This is a showcase of generic functional lenses in C++. The implementatoin is built with using of Variadic Templates
, some intresting (and valid) C++ hacks to make lenses composable and neat-looking. The library is just a demo for the talk and thus it provides only a few of most important combinators, namely: set()
, view()
, traverse()
, bind()
, infix literal combinator to
, over()
and other.
这是 C++ 中通用功能镜头的展示。该实现是使用 of 构建的Variadic Templates
,一些有趣的(和有效的)C++ hacks 使镜头可组合且外观整洁。图书馆是只是为了通话演示,因此它仅提供了几个最重要的组合程序,即:set()
,view()
,traverse()
,bind()
,缀文字组合子to
,over()
等。
(Note that there exist the 'C++ Lenses' project: but it's not about real 'lenses', it's about class properties with getters and setters in sense of C# or Java properties.)
(请注意,存在“C++ 镜头”项目:但它不是关于真正的“镜头”,而是关于在 C# 或 Java 属性意义上具有 getter 和 setter 的类属性。)
Quick example
快速示例
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");
- Functional 'Life': parallel celullar automata and comonads. (GitHub) (Slides (Eng)) (Talk (Rus))
- 功能性“生命”:平行细胞自动机和共生体。( GitHub) ( Slides (Eng)) ( Talk (Rus))
You have probably heard about monads. Monads are everywhere in talks about functional programming now. It's a buzzword. But what about comonads? I presented 1D and 2D celullar automata with the concept of comonads under the hood. The aim was to show how easy it is to move from the single-flow code to the parallel one using std::future as a Par monad. The project also benchmarks and compares two these approaches.
你可能听说过 monad。现在到处都在谈论函数式编程。这是一个流行词。但是共生呢?我展示了 1D 和 2D 元胞自动机以及引擎盖下共子的概念。目的是展示使用 std::future 作为 Par monad 从单流代码移动到并行代码是多么容易。该项目还对这两种方法进行了基准测试和比较。
Quick example
快速示例
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 };
}
- Pure functional
Software Transactional Memory (STM)
library that is calledcpp_stm_free
. (GitHub) (Slides (Eng)) (Talk (Rus)) (Tutorial (Eng)) (Dining Philosopher sample).
- 纯函数
Software Transactional Memory (STM)
库,称为cpp_stm_free
. ( GitHub) ( Slides (Eng)) ( Talk (Rus)) ( Tutorial (Eng)) ( Dining Philosopher 样本)。
This library is based on Free monad
and some other advanced ideas of Functional Programming. Its interface is similar to Haskell's native STM library. Transactions are monadically composable, pure functional, and there is a lot of useful monadic combinators to make designing of concurrent model more convenient and powerful. I've implemented the Dining Philosophers problemusing the library, and it works well. Here is a sample of some transaction for taking of forks by a philosopher:
该库基于Free monad
函数式编程的其他一些高级思想。它的接口类似于 Haskell 的原生STM 库。事务是单子可组合的,纯函数式的,并且有很多有用的单子组合器可以使并发模型的设计更加方便和强大。我已经使用图书馆实现了餐饮哲学家问题,并且效果很好。以下是哲学家拿叉子的一些交易示例:
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);
}
回答by Javier
I don't think that you can'tto true, real, functional programming in C++; but it's certainly not the easiest or natural way to use it. Also, you might just use a couple of functional-like idioms and not the whole mindset (i.e. 'fluent style')
我不认为你不能在 C++ 中进行真正的、真实的、函数式编程;但这肯定不是使用它的最简单或自然的方式。此外,您可能只使用一些类似功能的习语,而不是整个思维方式(即“流畅的风格”)
My advise would be to learn a functional language, maybe start with Scheme, then move to Haskell. Then use what you've learned when programming in C++. maybe you won't use an obvious functional style; but you might get the biggest advantages (i.e. using immutable structures).
我的建议是学习一门函数式语言,也许从 Scheme 开始,然后转向 Haskell。然后使用您在 C++ 编程时学到的知识。也许你不会使用明显的函数式风格;但您可能会获得最大的优势(即使用不可变结构)。