La programación funcional en C++ da bastante pereza. Se supone que el estilo en el que decidimos programar es aquel en el que seremos más productivos, cometeremos menos errores y podremos expresar mejor nuestra intención, ya que todos los programas pueden ser escritos en todos los paradigmas, y sin embargo cuando intentamos traer a C++ todo este asunto de las funciones de orden superior y mónadas que hemos aprendido de Haskell e intentamos componer nuestros programas a partir de ello nos encontramos teniendo que escribir demasiada paja que no está expresando intención ni haciéndonos más productivos, sino todo lo contrario. Y es que C++ no es Haskell, y cosas como fijar parámetros o crear funciones anónimas o de orden superior requiere mucho más tecleo, debido a la capacidad de C++ de expresar en detalle la forma del binario generado, capacidad que Haskell simplemente pasa por alto. Que C++ no sea Haskell también hace que la cultura sea diferente y por lo tanto que el código que ya hay escrito o que la forma en la que la gente escribe código sean diferentes. Pocas funciones cogen una cosa y devuelven otra, lo que hace que componer con el operador
monádico sea más doloroso porque tenemos que recurrir a lambdas más veces que las que no. La gente que intenta que C++ sea Haskell, proponiendo añadir funciones de continuación a clases como
o
, tal vez debería primero preguntarse si realmente es una forma viable de escribir código a gran escala. Es muy frustrante cuando en el intento de imitar los elegantes ejemplos de diapositiva de conferencia uno termina con unos churros ilegibles. La realidad es que, aunque el código de diapositiva puede permitirse ignorar los detalles, el código con el que uno lidia día a día está lleno de ellos, y es precisamente cuando entran en juego los detalles cuando el estilo funcional en C++ se vuelve más tedioso que útil.
Sin embargo, es cierto que hay una serie de ventajas inherentes a la programación funcional a las que desde luego que no queremos rechazar. La ausencia de estado global y el escaso y controladísimo número de mutaciones al estado del programa hacen que probar que el código es correcto sea muchísimo más fácil. El estilo funcional permite aumentar muchísimo la porción del proyecto que podemos demostrar que es correcta de forma automatizada y por lo tanto ahorrar horas en probar a mano y buscar problemas. También hace del código muchas veces casi trivial de paralelizar. La programación funcional aboga por el estado global inmutable y por que casi toda la mutación suceda en estado local, mientras que huye de lo que Kevlin Henney llama cuadrante de la sincronización, en el que por desgracia vive mayormente la orientación a objetos.

C++20 introduce por fin en el lenguaje las corrutinas, una abstracción que permite escribir código asíncrono en un estilo imperativo, mientras simplifica hasta casi eliminarla la complejidad de las funciones asíncronas, que pasan a parecer casi funciones normales. Las corrutinas suponen una alternativa a la forma tradicional orientada a objetos de escribir código asíncrono, mediante el uso de callbacks, pero también a la interfaz monádica de
basada en encadenar funciones de continuación. En vez de eso permite escribir una única función aparentemente imperativa en la que sin embargo el compilador introducirá los cambios necesarios para poder suspender y retomar la ejecución conforme el estado del programa y de aquello a lo que se está esperando lo permita. El lenguaje se encarga de toda la interacción con el objeto de la corrutina, algo parecido a un
. Por si esto no fuera suficiente, resulta que existe la posibilidad de usar la sintaxis de las corrutinas para simplificar mucho la forma de trabajar con tipos de error monádicos como
o
, haciendo que
signifique extraer el contenido, y si no lo hay devolver el error.
En resumen, las corrutinas permiten, de una forma similar a la notación
de Haskell, convertir constructos funcionales en imperativos, tanto para las mónadas asíncronas (
) como para las mónadas de error (
,
). Esto permite a C++ tener lo mejor de los dos mundos. Por un lado, puede tener interfaces funcionales, con sus facilidades para demostrar su corrección y para paralelizar. Por otro, la composición de estas funciones puede darse en un estilo imperativo, que es mucho más natural para C++ y por lo tanto resulta en código más corto, más simple y con una mayor proporción señal/ruido. Creo que, si se quiere programar en un estilo funcional en C++, ésta es precisamente la forma de hacerlo. Debemos entender que el constructo funcional por excelencia para la composición, la mónada, al menos en su definición tradicional, encuentra serios problemas de ergonomía al sacarlo de un lenguaje donde gran parte del diseño está dirigido a facilitar el trabajar con él, sobre todo al intentar llevarlo a un lenguaje que se acerca a su 40 cumpleaños y donde gran parte del diseño es anterior a que las mónadas salieran de círculos académicos muy específicos. La forma en la que C++ puede conseguir expresar composición fácilmente manteniendo interfaces funcionales es mediante mecanismos que permitan convertir el estilo funcional en imperativo dentro de la función, permitiendo programar de la forma que es más natural para las herramientas que da el lenguaje.
La ergonomía, aunque fácil de ignorar a primera vista, es crucial a la hora de diseñar lenguajes de programación y bibliotecas, pues si algo es usado o no muchas veces es dictado por lo fácil y cómodo que es de usar. Recordemos por ejemplo que prácticamente nadia usaba la mayoría de los algoritmos de
hasta C++11, cuando las lambdas hicieron cómodo el pasar predicados y funciones de comparación a los algoritmos, o que gran parte de la discusión sobre hacer cálculos en tiempo de compilación ha sido algo arcano e inaccesible para la mayoría de los programadores hasta que los argumentos de template variádicos,
y la estandarización de
bajaron el listón de conocimientos necesarios y de dificultad para poder hacer cosas. Hay un punto en el que el cambio de una mejora puramente ergonómica pasa de cuantitativo a cualitativo, y pasa a cambiar la forma en la que programamos, pues hace accesible algo que antes, por dificultad, por pereza, o por la razón que fuera, no lo era.
La única limitación de lo discutido en este texto, al menos en el estado en el que C++ y las corrutinas se encuentran a día de hoy, es que es imposible hacerlo funcionar para la mónada de lista, pues
sólo devuelve un único
. C++20 permite trabajar con secuencias en un estilo funcional con la biblioteca
, más inspirada en un estilo funcional tradicional y por lo tanto más afectada por los problemas arriba mencionados. De momento es demasiado pronto para intentar predecir hacia dónde irá el trabajar con secuencias en C++. Lo que toca ahora es probar
y otras bibliotecas parecidas como las
de Jonathan Boccara, ver si son eficaces resolviendo problemas del mundo real una vez fuera del mágico mundo de las diapositivas y si son o no la forma en la que queremos escribir nuestro código. De momento, la solución parece un poco cruda, demasiado parecida a un intento de copiar Haskell. Habrá que ver qué más se nos ocurre en el futuro.