Функциональное программирование на С++

Может ли кто-нибудь руководить мной, как выполнять функциональное программирование на С++? Есть ли какой-нибудь хороший онлайн-материал, который я могу назвать?

Обратите внимание, что я знаю о библиотеке FС++. Я хочу знать, как это сделать с помощью стандартной библиотеки С++.

Спасибо.

Ответ 1

Обновление в августе 2014 года: этот ответ был опубликован в 2009 году. С++ 11 значительно улучшил ситуацию для функционального программирования на С++, поэтому этот ответ больше не является точным. Я оставляю его ниже для исторической записи.

Поскольку этот ответ застрял как принятый, я превращаю его в сообщество Wiki. Не стесняйтесь совместно улучшить его, чтобы добавить настоящие советы по программированию функций с современным С++.


Вы не можете выполнять функциональное программирование true с помощью С++. Все, что вы можете сделать, это приблизить его с большим количеством боли и сложности (хотя в С++ 11 это немного проще). Поэтому этот подход не рекомендуется. С++ поддерживает другие парадигмы программирования относительно хорошо, и IMHO не следует склонять к парадигмам, которые он поддерживает менее эффективно - в конце он сделает нечитаемый код, который понимает автор.

Ответ 2

Вы можете выполнить удивительное количество "функционального программирования" с современным С++. Фактически, этот язык развивается в этом направлении с момента его "стандартизации".

Стандартная библиотека содержит алгоритмы, аналогичные картам, сокращениям и т.д. (for_each, transform, mixed_sum...). Следующая версия С++ 0x содержит множество функций, позволяющих программистам работать с ними в более функциональном стиле (лямбда-выражения и т.д.).

Посмотрите на различные библиотеки Boost для большей забавы. Просто чтобы проиллюстрировать, что стандартный С++ содержит много функциональной добра, здесь факториальная функция в стиле продолжения прохождения в стандартном С++.

#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;
}

Хорошо, я немного солгал. Это факторный функтор. В конце концов, закрытие - это объекты с бедными людьми... и наоборот. Большинство функциональных методов, используемых в С++, основаны на использовании функторов (т.е. Объектов функций) --- вы увидите это широко в STL.

Ответ 3

Я не думаю, что вы не можете выполнить истинное, реальное, функциональное программирование на С++; но это, конечно, не самый простой или естественный способ его использования. Кроме того, вы можете просто использовать несколько функционально-подобных идиом, а не весь образ мышления (т.е. "Свободный стиль" )

Мое посоветование - изучить функциональный язык, возможно, начать с Схемы, а затем переехать в Хаскелл. Затем используйте то, что вы узнали при программировании на С++. возможно, вы не будете использовать очевидный функциональный стиль; но вы можете получить самые большие преимущества (т.е. использовать неизменяемые структуры).

Ответ 4

Рассмотрим мои 3 исследовательских проекта:

Этот проект является рабочим прототипом игры "Амбер". Код демонстрирует многие основные функциональные концепции: immutability, lambdas, monads, combinators, pure functions, declarative code design. Он использует функции Qt С++ и С++ 11.

Для быстрого примера см., как задачи могут быть привязаны к одной большой задаче, которая изменит мир янтаря при его применении:

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;
};

Это демонстрация общих функциональных линз в С++. Реализатор построен с использованием Variadic Templates, некоторых интересных (и действительных) С++-хаков, чтобы сделать объективы сложными и аккуратными. Библиотека представляет собой просто демонстрацию для разговора и, таким образом, она содержит лишь несколько из наиболее важных комбинаторов, а именно: set(), view(), traverse(), bind(), инфикс-литеральный комбинатор to, over() и другие.

(Обратите внимание, что существуют "С++ Lenses" проект: но это не касается реальных "линз", это о свойствах класса с геттерами и сеттеры в смысле свойств С# или Java.)

Быстрый пример

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");
  • Функциональная "Жизнь": параллельные целуллярные автоматы и комонады. (GitHub) (Слайды (Eng)) (Talk (Rus))

Вероятно, вы слышали о монадах. Монады повсюду говорят о функциональном программировании. Это модное слово. Но как насчет 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 };
}

Ответ 5

Существует книга под названием Functional C от Pieter Hartel и Henk Muller, которая может помочь. Если он все еще доступен. Ссылка на некоторую информацию на нем здесь. IIRC было не так уж плохо.

Ответ 6

Возможно, немного поздно, но для кого-то другого - я использую lua как расширение функционального программирования для С++, и это здорово. lua