Какие инструменты существуют для функционального программирования в C?
Я много думал в последнее время о том, как заниматься функциональным программированием на C (не C++). Очевидно, что C является процедурным языком и на самом деле не поддерживает функциональное программирование изначально.
существуют ли какие-либо расширения компилятора/языка, которые добавляют некоторые конструкции функционального программирования к языку? НКУ предусматривает вложенные функции как расширение языка; вложенные функции могут обращаться к переменным из родительского кадра стека, но это до зрелых закрытий еще далеко.
например, одна вещь, которая, как я думаю, может быть действительно полезной в C, заключается в том, что в любом месте, где ожидается указатель функции, вы можете передать лямбда-выражение, создав замыкание, которое распадается на указатель функции. C++0x будет включать лямбда-выражения (что я считаю потрясающим); однако я ищу инструменты, применимые к прямому C.
[Edit] чтобы уточнить, я не пытаюсь решить конкретную проблему в C это было бы более подходящим для функционального программирования; мне просто интересно, какие инструменты там есть, если бы я хотел это сделать.
13 ответов:
FFCALL позволяет создавать замыкания в C --
callback = alloc_callback(&function, data)возвращает указатель на функцию такую, чтоcallback(arg1, ...)эквивалентен вызовуfunction(data, arg1, ...). Однако вам придется обрабатывать сборку мусора вручную.кроме того, блоки были добавлены в вилку Apple GCC; они не являются указателями функций, но они позволяют вам передавать лямбды, избегая необходимости создавать и освобождать хранилище для захваченных переменных вручную (эффективно, некоторые копирование и ссылка подсчет происходит, скрытый за некоторыми синтаксическими сахарами и библиотеками времени выполнения).
вы можете использовать вложенные функции GCC для имитации лямбда-выражений, на самом деле, у меня есть макрос, чтобы сделать это для меня:
#define lambda(return_type, function_body) \ ({ \ return_type anon_func_name_ function_body \ anon_func_name_; \ })используйте вот так:
int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; });
функциональное программирование-это не лямбда, это все о чистых функциях. Таким образом, следующие широко продвигают функциональный стиль:
используйте только аргументы функции, не используйте глобальное состояние.
минимизировать побочные эффекты, т. е. printf, или любой IO. Возвращает данные, описывающие IO, которые могут быть выполнены вместо того, чтобы вызывать побочные эффекты непосредственно во всех функциях.
этого можно достигнуть в простом c, никакой потребности для магия.
книга Хартеля и Мюллера,Функциональный C, в настоящее время (2012-01-02) можно найти по адресу:http://eprints.eemcs.utwente.nl/1077/ (есть ссылка на PDF версию).
главное, что приходит на ум-это использование генераторов кода. Вы хотели бы программировать на другом языке, который обеспечивал функциональное программирование, а затем генерировать код C из этого?
Если это не привлекательный вариант, то вы можете злоупотреблять CPP, чтобы получить часть пути туда. Макросистема должна позволить вам эмулировать некоторые идеи функционального программирования. Я слышал, что gcc реализуется таким образом, но я никогда не проверял.
C может конечно, передайте функции с помощью указателей функций, основными проблемами являются отсутствие замыканий, и система типов имеет тенденцию мешать. Вы можете исследовать более мощные макросистемы, чем CPP, такие как M4. Я думаю, в конечном счете, я предлагаю, чтобы true C не справлялся с задачей без больших усилий, но вы могли бы расширить C, чтобы сделать его до задачи. Это расширение будет выглядеть наиболее похоже на C, если вы используете CPP, или вы можете перейти на другой конец спектра и сгенерировать код C из некоторых другой язык.
Если вы хотите реализовать закрытие, вам нужно будет получить groady с языком ассемблера и заменой стека/управлением. Не рекомендуя против него, просто говоря, что это то, что вам придется сделать.
Не уверен, как вы будете обрабатывать анонимные функции в C. На машине фон Неймана вы можете выполнять анонимные функции в asm.
посмотрите на книгу Хартеля и Мюллера,Функциональный C
http://www.ub.utwente.nl/webdocs/ctit/1/00000084.pdf
http://www.cs.bris.ac.uk / ~henkm/f2c/index.html
предпосылкой для функционального стиля программирования является функция первого класса. Он может быть смоделирован в портативном C, если вы допускаете следующее:
- ручное управление привязками лексического объема, aka замыкания.
- ручное управление временем жизни переменных функции.
- альтернативный синтаксис приложения/вызова функции.
/* * 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;во время выполнения такого кода может быть как ниже
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 });по сути мы имитируем функция первого класса с замыканиями, представленными как пара функций / аргументов плюс куча макросов. Полный код можно найти здесь.
The Феликс язык компилируется в C++. Может быть, это может быть шаг камень, если вы не возражаете C++.
способ, которым я занимался функциональным программированием на C, состоял в том, чтобы написать интерпретатор функционального языка в C. я назвал его Fexl, что является сокращением от "языка выражения функций"."
интерпретатор очень мал, компилируется до 68K в моей системе с включенным-O3. Это тоже не игрушка - я использую ее для всего нового производственного кода, который я пишу для своего бизнеса (веб-учет инвестиционных партнерств.)
теперь я пишу код C только для (1) добавить встроенный функция, которая вызывает системную процедуру (например, fork, exec, setrlimit и т. д.), или (2) оптимизировать функцию, которая в противном случае могла бы быть записана в Fexl (например, поиск подстроки).
модульный механизм основан на концепции "контекста". Контекст-это функция (написанная на языке Fexl), которая сопоставляет символ с его определением. Когда вы читаете файл Fexl, вы можете разрешить его с любым контекстом, который вам нравится. Это позволяет создавать пользовательские среды или запускать код в ограниченном режиме "песочница."
Не знаю о C. Есть некоторые функциональные возможности в Objective-C хотя, GCC на OSX также поддерживает некоторые функции, однако я бы снова рекомендовал начать использовать функциональный язык, есть много упомянутых выше. Я лично начал со схемы, есть несколько отличных книг, таких как The Little Schemer, которые могут помочь вам сделать это.
Что это такое о C, что вы хотите сделать функциональным, синтаксис или семантика? Семантика функционального программирования, безусловно, может быть добавлена в компилятор C, но к тому времени, когда вы закончите, у вас будет по существу эквивалент одного из существующих функциональных языков, таких как Scheme, Haskell и т. д.
было бы лучше использовать время, чтобы просто изучить синтаксис тех языков, которые непосредственно поддерживают эту семантику.
Comments