当前位置:  开发笔记 > 编程语言 > 正文

C++中的函数式编程

如何解决《C++中的函数式编程》经验,为你挑选了4个好方法。

有人可以指导我如何在C++中进行函数式编程吗?我可以参考哪些好的在线资料?

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

谢谢.



1> Derrick Turk..:

您可以使用现代C++实现惊人数量的"函数式编程"风格.事实上,自从标准化以来,语言一直在朝这个方向发展.

标准库包含类似于map,reduce等的算法(for_each,transform,adjacent_sum ...).下一个版本C++ 0x包含许多功能,旨在让程序员以更实用的方式(lambda表达式等)使用它们.

查看各种Boost库以获得更多乐趣.为了说明标准C++包含大量的功能优点,这里是标准C++中延续传递风格的阶乘函数.

#include 

// 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中广泛地看到它.


"毕竟,关闭是一个穷人的对象......反之亦然." 我不同意.是的,你可以使用另一个实现一个......但是如果你想基于仿函数重新实现对象会发生什么?一个可怕的烂摊子.如果你在基于闭包的对象上重新实现闭包?它(几乎)解开了"本土"概念.因此,我认为闭包是_far_更适合作为'基元'而不是对象(并且不会让我开始关于基于类的对象!)

2> Eli Bendersk..:

2014年8月更新:这个答案发布于2009年.C++ 11改进了C++中函数式编程的重要性,因此这个答案不再准确.我将它留在下面以获得历史记录.

由于这个答案被认为是被接受的答案 - 我将其转变为社区Wiki.随意协作改进它以添加有关现代C++的函数编程的真实技巧.


你不能用C++ 进行真正的函数式编程.所有你能做的就是用大量的痛苦和复杂性来近似它(尽管在C++ 11中它更容易一些).因此,不建议采用这种方法.C++相对较好地支持其他编程范例,并且IMHO不应该倾向于它支持不太好的范例 - 最终它将使得只有作者理解的不可读代码.


这不是**在C++中编程FP的有趣之处.有趣的程序FP与Lisp或Haskell
但我必须坚持:-)这比用C++学习如何做更少的时间
我不认为这是公平的.当然,你不能完全避免使用C++中的副作用,但是你可以在采用功能方法方面走得很远.像 Higher Order Perl 这样的书籍表明功能方法可以用于命令式语言.此外,C++的各种功能使得功能样式比C语言更容易采用.
没有.纯娱乐.:)

3> graninas..:

UPD 2018年12月

我已经创建了一个完整的材料列表,您可以在其中找到文章,讲座,截屏视频,论文,图书馆和展示:

C++中的函数式编程


考虑我的4个研究项目:

C++中的功能和声明设计.(GitHub)(幻灯片(Rus))(谈话(Rus))

这个项目是'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;
};

C++中的镜头.(GitHub)(幻灯片(Eng))(谈话(Rus))

这是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 cars = {car1, car2};

auto zoomer = traversed() to modelL();

std::function variator = [](std::string) { return std::string("BMW x6"); };
std::vector result = over(zoomer, cars, variator);

QVERIFY(result.size() == 2);
QVERIFY(result[0].model == "BMW x6");
QVERIFY(result[1].model == "BMW x6");

功能性"生命":平行细胞自动机和组合.(GitHub)(幻灯片(Eng))(谈话(Rus))

你可能听说过monads.Monads现在到处都在讨论函数式编程.这是一个流行语.但是comonads怎么样?我提出了1D和2D celullar自动机与引擎盖下的comonads概念.目的是展示使用std :: future作为Par monad从单流代码转移到并行代码是多么容易.该项目还对这两种方法进行了基准测试和比较.

快速举例

template 
UUB fmap(
    const func& f,
    const UUUUA& uuu)
{
    const func 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 };
}

Software Transactional Memory (STM)被称为纯函数库cpp_stm_free.(GitHub)(幻灯片(Eng))(谈话(Rus))(教程(Eng))(餐饮哲学家样本).

该库基于Free monad功能编程的一些其他高级思想.它的界面类似于Haskell的原生STM库.事务是可单一组合的,纯函数式的,并且有许多有用的monadic组合器可以使并发模型的设计更加方便和强大.我使用图书馆实现了餐饮哲学家的问题,而且效果很好.以下是哲学家采取分叉的一些交易样本:

STML takeFork(const TFork& tFork) {
    return withTVar(tFork, [=](const Fork& fork) {
       if (fork.state == ForkState::Free) {
           return writeTVar(tFork, Fork {fork.name, ForkState:Taken});
       }
       else {
           return retry();
       }
    });
}

STML takeForks(const TForkPair& forks) {
    STML lm = takeFork(forks.left);
    STML rm = takeFork(forks.right);
    return sequence(lm, rm);
}



4> Javier..:

我不认为你不能用C++进行真正的,真实的函数式编程; 但它肯定不是使用它的最简单或最自然的方式.此外,你可能只是使用一些功能性的习语,而不是整个心态(即'流畅的风格')

我的建议是学习一种函数式语言,可能从Scheme开始,然后转到Haskell.然后使用您在C++中编程时学到的知识.也许你不会使用明显的功能风格; 但是你可能会获得最大的优势(即使用不可变结构).

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有