2009-12-30 9 views
49

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

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

Спасибо.

+17

Вы лучше с помощью функционального языка программирования (LISP, Haskell, Scheme, ...). Таким образом, вы уверены, что вы выполняете функциональное программирование. –

+3

Какие функции FP вы ищете? Boost предоставляет некоторые FP-подобные библиотеки (mpl, function, lambda и т. Д.), А некоторые из них будут в C++ 0x и уже находятся в TR1. – Macke

+0

@Brian: Я просто хочу почувствовать FP, не изучая новый язык. И прямо сейчас я знаю только C++ и Java. И Java, я думаю, будет еще хуже для FP. –

ответ

23

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

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


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

+4

Ничего. Просто для удовольствия. :) –

+15

Это ** НЕ ** весело программирование FP в C++. Для забавной программы FP с Lisp или Haskell –

+1

Я бы наверняка изучил язык FP когда-нибудь. Но сейчас у меня нет на это времени. –

5

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

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

+0

как кто-то, изучающий haskell, мне было бы интересно узнать, почему вы предлагаете схему в первую очередь. –

+0

Я раньше видел код схемы. Для меня это похоже на все китайско-японское. : | –

+0

Хорошо. Я проверю некоторые языки FP. Спасибо за ответ! –

45

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

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

Загляните в различные библиотеки 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; 
} 

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

+1

Красивый пример. Но выбор имен идентификаторов, которые я должен сказать, очень плох, поэтому, если бы вы могли отредактировать свой пост и использовать несколько лучших имен идентификаторов. Кстати, я поддержал вас. Благодаря! :) –

+2

«В конце концов, закрытие - это объекты бедного человека ... и наоборот». я должен не согласиться. да, вы можете реализовать один с другим ... но что произойдет, если вы хотите переопределить объекты на основе функторов? ужасный беспорядок. и если вы переопределите закрытие поверх объектов, основанных на закрытии? он почти полностью раскрывается в «родных» концепциях. Таким образом, я думаю, что замыкания являются более подходящими как «примитивы», чем объекты (и не заставляйте меня начинать с объектов класса!) – Javier

+0

Спасибо, Джейкоб! Я немного почистил пример. Он никогда не предназначался для публичного показа; Я только что прочитал Lambda: The Ultimate Imperative и хотел попробовать CPS на C++. Но затем я увидел этот вопрос и просто должен был поделиться ... –

1

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

+0

Согласно описанию, эта книга учит императивному программированию людям, пришедшим с функциональных языков. Не как выполнять функциональное программирование на C (что wou я бы стал немного более болезненным, чем это делал на C++, я бы предположил). – sepp2k

+0

Якобы это так, но вам нечего остановить в противоположном направлении. Это хорошо работает для этого и дает вам некоторые указания о том, как программировать C в функциональном стиле. – rvirding

0

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

+0

Действительно ли это предложение просто использовать другой язык? – CyberFox

4

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

Этот проект является рабочим прототипом игры 'Амбер'. Код демонстрирует многие из основных функциональных концепций: immutability, lambdas, monads, combinators, pure functions, declarative code design. Он использует Qt C++ и C++ 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; 
}; 

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

(Обратите внимание, что существуют "линзы C++ project: но это не о реальных«линз», это о свойствах класса с добытчиками и сеттеров в смысле C# или 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"); 
  • Функциональная 'Жизнь': параллельные celullar автоматы и comonads. (GitHub) (Slides (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 }; 
} 
Смежные вопросы