Функциональное программирование на С++
Может ли кто-нибудь руководить мной, как выполнять функциональное программирование на С++? Есть ли какой-нибудь хороший онлайн-материал, который я могу назвать?
Обратите внимание, что я знаю о библиотеке 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");
Вероятно, вы слышали о монадах. Монады повсюду говорят о функциональном программировании. Это модное слово. Но как насчет 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