¿Qué herramientas existen para la progtwigción funcional en C?

Últimamente he estado pensando mucho en cómo hacer la progtwigción funcional en C ( no en C ++). Obviamente, C es un lenguaje de procedimiento y realmente no admite la progtwigción funcional de forma nativa.

¿Hay alguna extensión de comstackdor / lenguaje que agregue algunas construcciones de progtwigción funcional al lenguaje? GCC proporciona funciones anidadas como una extensión de lenguaje; Las funciones anidadas pueden acceder a las variables desde el marco de la stack principal, pero todavía está muy lejos de los cierres maduros.

Por ejemplo, una cosa que creo que podría ser realmente útil en C es que en cualquier lugar donde se espera un puntero de función, podría pasar una expresión lambda, creando un cierre que se desintegra en un puntero de función. C ++ 0x incluirá expresiones lambda (que creo que es increíble); Sin embargo, estoy buscando herramientas aplicables a la recta C.

[Editar] Para aclarar, no estoy tratando de resolver un problema particular en C que sea más adecuado para la progtwigción funcional; Solo tengo curiosidad por saber qué herramientas hay disponibles si quisiera hacerlo.

FFCALL le permite crear cierres en C: callback = alloc_callback(&function, data) devuelve un puntero a función tal que callback(arg1, ...) es equivalente a llamar a function(data, arg1, ...) . Sin embargo, tendrás que manejar la recolección de basura manualmente.

En relación con esto, se han agregado bloques a la bifurcación de Apple de GCC; no son punteros de función, pero le permiten pasar lambda evitando la necesidad de crear y almacenar a mano las variables capturadas (efectivamente, ocurre algo de copia y conteo de referencias, escondido detrás de algunas bibliotecas sintácticas de azúcar y tiempo de ejecución).

Puedes usar las funciones anidadas de GCC para simular expresiones lambda, de hecho, tengo una macro para hacerlo por mí:

 #define lambda(return_type, function_body) \ ({ \ return_type anon_func_name_ function_body \ anon_func_name_; \ }) 

Use así:

 int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; }); 

La progtwigción funcional no se trata de lambdas, se trata de funciones puras. Así que lo siguiente promueve ampliamente el estilo funcional:

  1. Solo use argumentos de función, no use estado global.

  2. Minimice los efectos secundarios, por ejemplo, printf, o cualquier IO. Devuelva los datos que describen la IO que se puede ejecutar en lugar de causar los efectos secundarios directamente en todas las funciones.

Esto se puede lograr en c simple, sin necesidad de magia.

El libro de Hartel & Muller, Functional C , se puede encontrar hoy en día (2012-01-02) en: http://eprints.eemcs.utwente.nl/1077/ (hay un enlace a la versión en PDF).

Lo principal que viene a la mente es el uso de generadores de código. ¿Estaría dispuesto a progtwigr en un lenguaje diferente que proporcionara la progtwigción funcional y luego generar el código C a partir de eso?

Si esa no es una opción atractiva, entonces podría abusar de CPP para obtener parte del camino. El sistema de macros debería permitirle emular algunas ideas de progtwigción funcional. He oído decir que gcc se implementa de esta manera, pero nunca lo he comprobado.

Por supuesto, C puede pasar funciones mediante el uso de punteros de función, los principales problemas son la falta de cierres y el sistema de tipos tiende a interferir. Podría explorar sistemas de macros más potentes que CPP, como M4. Supongo que, en última instancia, lo que sugiero es que la verdadera C no está a la altura de la tarea sin un gran esfuerzo, pero se podría extender C para que esté a la altura de la tarea. Esa extensión se parecería más a C si usas CPP o podrías ir al otro extremo del espectro y generar código C desde otro idioma.

Si desea implementar cierres, tendrá que abrirse camino con el lenguaje ensamblador y la administración / intercambio de stack. No lo recomiendo, solo digo que eso es lo que tendrás que hacer.

Sin embargo, no estoy seguro de cómo manejar las funciones anónimas en C. En una máquina de von Neumann, podría realizar funciones anónimas en asm.

El requisito previo para el estilo de progtwigción funcional es una función de primera clase. Se podría simular en C portátil si se tolera a continuación:

  • Gestión manual de enlaces de ámbito léxico, también conocido como cierres.
  • Gestión manual de las variables de función de toda la vida.
  • Sintaxis alternativa de la función de aplicación / llamada.
 /* * with constraints desribed above we could have * good approximation of FP style in plain C */ int increment_int(int x) { return x + 1; } WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS(increment, increment_int); map(increment, list(number(0), number(1)); // --> list(1, 2) /* composition of first class function is also possible */ function_t* computation = compose( increment, increment, increment ); *(int*) call(computation, number(1)) == 4; 

El tiempo de ejecución de dicho código podría ser tan pequeño como uno de los siguientes

 struct list_t { void* head; struct list_t* tail; }; struct function_t { void* (*thunk)(list_t*); struct list_t* arguments; } void* apply(struct function_t* fn, struct list_t* arguments) { return fn->thunk(concat(fn->arguments, arguments)); } /* expansion of WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS */ void* increment_thunk(struct list_t* arguments) { int x_arg = *(int*) arguments->head; int value = increment_int(x_arg); int* number = malloc(sizeof *number); return number ? (*number = value, number) : NULL; } struct function_t* increment = &(struct function_t) { increment_thunk, NULL }; /* call(increment, number(1)) expands to */ apply(increment, &(struct list_t) { number(1), NULL }); 

En esencia, imitamos la función de primera clase con cierres representados como un par de funciones / argumentos más un grupo de macroses. El código completo se puede encontrar aquí .

Bueno, algunos lenguajes de progtwigción están escritos en C. Y algunos de ellos admiten funciones como ciudadanos de primera clase, los lenguajes en esa área son ecl (embbedabble common lisp IIRC), Gnu Smalltalk (gst) (Smalltalk tiene bloques), luego hay bibliotecas para “cierres”, por ejemplo, en glib2 http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure que al menos se acercó a la progtwigción funcional. Entonces, tal vez el uso de algunas de esas implementaciones para realizar la progtwigción funcional puede ser una opción.

Bueno, o puedes ir a aprender Ocaml, Haskell, Mozart / Oz o similares 😉

Saludos

El lenguaje Felix comstack a C ++. Tal vez eso podría ser un escalón, si no te importa C ++.

La forma en que hice la progtwigción funcional en C fue escribir un intérprete de lenguaje funcional en C. Lo llamé Fexl, que es la abreviatura de “Lenguaje de expresión de función”.

El intérprete es muy pequeño, comstackndo hasta 68K en mi sistema con -O3 habilitado. Tampoco es un juguete, lo estoy usando para todos los nuevos códigos de producción que escribo para mi negocio (contabilidad basada en la web para sociedades de inversión).

Ahora escribo el código C solo para (1) agregar una función incorporada que llama a una rutina del sistema (por ejemplo, fork, exec, setrlimit, etc.), o (2) optimizar una función que de lo contrario podría escribirse en Fexl (por ejemplo, buscar para una subcadena).

El mecanismo del módulo se basa en el concepto de “contexto”. Un contexto es una función (escrita en Fexl) que mapea un símbolo a su definición. Cuando lees un archivo Fexl, puedes resolverlo con el contexto que quieras. Esto le permite crear entornos personalizados o ejecutar código en un “recinto de seguridad” restringido.

http://fexl.com

No sé acerca de C. Sin embargo, hay algunas funciones funcionales en Objective-C, GCC en el OSX también admite algunas funciones, sin embargo, una vez más recomendaría comenzar a usar un lenguaje funcional, hay muchos mencionados anteriormente. Yo personalmente comencé con el esquema, hay algunos libros excelentes como The Little Schemer que pueden ayudarte a hacerlo.

¿De qué se trata C que quieres que sea funcional, la syntax o la semántica? La semántica de la progtwigción funcional sin duda podría agregarse al comstackdor de C, pero para el momento en que haya terminado, esencialmente tendría el equivalente de uno de los lenguajes funcionales existentes, como Scheme, Haskell, etc.

Sería un mejor uso del tiempo simplemente aprender la syntax de los idiomas que soportan directamente esa semántica.