2009-12-30 24 views
49

¿Alguien me puede guiar cómo funciona la programación en C++? ¿Hay algún buen material en línea al que pueda referirme?Programación funcional en C++

Tenga en cuenta que sé acerca de la biblioteca FC++. Quiero saber cómo hacer eso solo con la biblioteca estándar de C++.

Gracias.

+17

Usted es mejor de usar un lenguaje de programación funcional (LISP, Haskell, Esquema, ...). De esta manera, está seguro de que lo que está haciendo es, de hecho, una programación funcional. –

+3

¿Qué tipo de características de FP está buscando? Boost proporciona algunas bibliotecas tipo FP (mpl, función, lambda, etc.) y algunas de ellas estarán en C++ 0x y ya están en TR1. – Macke

+0

@Brian: Solo quiero sentirme de FP sin aprender un nuevo idioma. Y ahora solo sé C++ y Java. Y Java supongo que sería una opción aún peor para FP. –

Respuesta

23

Actualización Agosto de 2014: esta respuesta se publicó en 2009. C++ 11 mejoró considerablemente las cosas para la programación funcional en C++, por lo que esta respuesta ya no es precisa. Lo dejo abajo para un registro histórico.

Dado que esta respuesta quedó como la aceptada, la estoy convirtiendo en una Wiki de la comunidad. Siéntase libre de mejorar colaborativamente para agregar consejos reales sobre programación de funciones con C++ moderno.


No se puede hacer cierto programación funcional con C++. Todo lo que puedes hacer es aproximarlo con una gran cantidad de dolor y complejidad (aunque en C++ 11 es un poco más fácil). Por lo tanto, este enfoque no es recomendable. C++ es compatible con otros paradigmas de programación relativamente bien, y en mi humilde opinión no debería inclinarse por los paradigmas que admite menos; al final, hará que el código ilegible solo lo entienda el autor.

+4

Nada. Solo por diversión. :) –

+15

Es ** NO ** programación divertida FP en C++. Para el divertido programa FP con Lisp o Haskell –

+1

seguramente aprenderé el lenguaje FP algún día. Pero ahora no tengo tiempo para eso. –

5

No creo que no puede a la programación real, real, funcional en C++; pero ciertamente no es la forma más fácil o natural de usarlo. Además, puede usar un par de modismos funcionales y no toda la mentalidad (es decir, 'estilo fluido')

Mi consejo sería aprender un lenguaje funcional, tal vez comenzar con Scheme, luego pasar a Haskell. Luego usa lo que has aprendido al programar en C++. tal vez no uses un estilo funcional obvio; pero puede obtener las mayores ventajas (es decir, usar estructuras inmutables).

+0

como alguien aprendiendo Haskell, me interesaría saber por qué sugieres el esquema primero. –

+0

He visto algún código Scheme antes. A mí me parece todo chino-japonés. : | –

+0

Bien. Voy a ver un poco de lenguaje FP. ¡Gracias por la respuesta! –

45

Puede lograr una sorprendente cantidad de estilo de "programación funcional" con el moderno C++. De hecho, el lenguaje ha tenido una tendencia en esa dirección desde su 'estandarización'.

La biblioteca estándar contiene algoritmos análogos a map, reduce, etc (for_each, transform, adjacent_sum ...). La próxima revisión, C++ 0x, contiene muchas características diseñadas para que los programadores puedan trabajar con ellas en un estilo más funcional (expresiones lambda, etc.).

Mire en las diversas bibliotecas de Boost para más diversión. Solo para ilustrar que el estándar C++ contiene un montón de bondad funcional, aquí hay una función factorial en el estilo de continuación de paso en C++ estándar.

#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, mentí un poco. Es un factorial functor. Después de todo, los cierres son objetos de un pobre hombre ... y viceversa. La mayoría de las técnicas funcionales utilizadas en C++ se basan en el uso de funtores (es decir, objetos funcionales); esto se verá ampliamente en el STL.

+1

Buen ejemplo. Pero la elección de los nombres de los identificadores que debo decir es muy mala, así que si pudiera, por favor edite su publicación y use algunos mejores nombres de identificación. Te he votado por el camino. ¡Gracias! :) –

+2

"Después de todo, los cierres son objetos de un pobre ... y viceversa". tengo que estar en desacuerdo sí, puede implementar uno usando el otro ... pero, ¿qué sucede si quiere volver a implementar objetos basándose en funtores? un horrible desastre. y si vuelves a aplicar cierres encima de objetos basados ​​en cierres? se desentraña (casi) a los conceptos 'nativos'. Por lo tanto, creo que los cierres son mucho más apropiados como 'primitivos' que como objetos (¡y no me permiten comenzar con los objetos basados ​​en clases!) – Javier

+0

¡Gracias, Jacob! Limpié el ejemplo un poco. Nunca fue pensado para exhibición pública; Acabo de leer Lambda: The Ultimate Imperative un día y quería probar CPS en C++. Pero luego vi esta pregunta y simplemente tuve que compartir ... –

1

Hay un libro llamado Funcional C de Pieter Hartel y Henk Muller que podría ayudar. Si todavía está disponible. Un enlace a información sobre él es here. IIRC no fue tan malo.

+0

Según la descripción, ese libro enseña la programación imperativa a las personas que provienen de los lenguajes funcionales. No cómo hacer la programación funcional en C (que Sería un poco más doloroso que hacerlo en C++, me imagino). – sepp2k

+0

Ostensiblemente esto es así, pero no hay nada que te impida usar en la dirección opuesta. Funciona bastante bien para eso y le da algunas indicaciones sobre cómo programar C en un estilo funcional. – rvirding

0

Probablemente un poco tarde, pero para cualquier otra persona que busque - Utilizo lua como una extensión de programación funcional para C++ y es genial.lua

+0

¿Es realmente una sugerencia solo usar otro idioma? – CyberFox

4

considerar mis proyectos de investigación 3:

Este proyecto es un prototipo de trabajo del juego 'Amber'. El código demuestra muchos de los principales conceptos funcionales: immutability, lambdas, monads, combinators, pure functions, declarative code design. Utiliza las características Qt C++ y C++ 11.

Para un ejemplo rápido, ver cómo las tareas se pueden encadenar en una gran tarea que va a modificar el mundo del ámbar cuando se aplica:

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

Esta es una muestra de lentes funcionales genéricos en C++. La implementación está construida con el uso de Variadic Templates, algunos hacks de C++ interesantes (y válidos) para hacer que las lentes sean compostables y aseadas. La biblioteca es solo una demostración de la charla y proporciona solo algunos de los más importantes combinadores, a saber: set(), view(), traverse(), bind(), infix literal combinator to, over() y otros.

(Tenga en cuenta que existen los 'C++ Lenses' project: pero no se trata de 'lentes' reales, se trata de propiedades de la clase con captadores y definidores en el sentido de C propiedades de Java # o.)

Ejemplo rápido

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"); 

es probable que haya oído hablar de las mónadas. Las mónadas están en todas partes en conversaciones sobre programación funcional ahora. Es una palabra de moda. ¿Pero qué hay de las comonads? Presenté autómatas celulares 1D y 2D con el concepto de comonads bajo el capó. El objetivo era mostrar cuán fácil es pasar del código de flujo único al paralelo utilizando std :: future como mónada Par. El proyecto también compara y compara dos de estos enfoques.

Ejemplo rápido

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