Высший порядок функционирует в C

Есть ли "надлежащий" способ реализовать функции высшего порядка в C.

Мне главным образом любопытно на предмет вещей как мобильность и правильность синтаксиса здесь и если существует больше чем один путь, каковы достоинства и дефекты.

Править: Причина, которую я хочу знать, как создать функции высшего порядка, состоит в том, что я записал систему для преобразования списков PyObject (который Вы получаете при вызове сценариев Python) в список структур C, содержащих те же данные, но организованный способом не иждивенец на python.h библиотеках. Таким образом, мой план состоит в том, чтобы иметь функцию, которая выполняет итерации через список pythonic и вызывает функцию на каждом объекте в списке и помещает результат в список, который это затем возвращает.

Таким образом, это - в основном мой план:

typedef gpointer (converter_func_type)(PyObject *)

gpointer converter_function(PyObject *obj)
{
    // do som stuff and return a struct cast into a gpointer (which is a void *)
}

GList *pylist_to_clist(PyObject *obj, converter_func_type f)
{
   GList *some_glist;
   for each item in obj
   {
       some_glist = g_list_append(some_glist, f(item));
   }
   return some_glist;
}

void some_function_that_executes_a_python_script(void)
{
   PyObject *result = python stuff that returns a list;
   GList *clist = pylist_to_clist(result, converter_function);
}

И к clearify вопрос: Я хочу знать, как выполнить в этом более безопасном и более корректном C. Я действительно хотел бы сохранить стиль функции высшего порядка, но если это хмурится на, я значительно ценю способы сделать этот некоторый другой путь.

17
задан Hobblin 29 March 2010 в 14:18
поделиться

7 ответов

Если вы заинтересованы в том, чтобы сделать это на простом C, вам нужно не забыть включить опцию передачи в контексте указателя от вызывающего функтора (функции более высокого порядка) к переданной функции. Это позволяет вам имитировать достаточное закрытие, чтобы вы могли заставить вещи работать достаточно легко. На что указывает этот указатель... ну, это должно быть void* в API функтора (или один из многих псевдонимов для него, таких как gpointer в мире GLib или ClientData в Tcl C API).

[EDIT]: Чтобы использовать/адаптировать свой пример:

typedef gpointer (converter_func_type)(gpointer,PyObject *)

gpointer converter_function(gpointer context_ptr,PyObject *obj)
{
    int *number_of_calls_ptr = context_ptr;
    *number_of_calls_ptr++;
    // do som stuff and return a struct cast into a gpointer (which is a void *)
}

GList *pylist_to_clist(PyObject *obj, converter_func_type f, gpointer context_ptr)
{
   GList *some_glist;
   for each item in obj
   {
       some_glist = g_list_append(some_glist, f(context_ptr,item));
   }
   return some_glist;
}

void some_function_that_executes_a_python_script(void)
{
   int number_of_calls = 0;
   PyObject *result = python stuff that returns a list;
   GList *clist = pylist_to_clist(result, converter_function, &number_of_calls);
   // Now number_of_calls has how often converter_function was called...
}

Это тривиальный пример того, как это сделать, но он должен показать вам путь.

4
ответ дан 30 November 2019 в 11:26
поделиться

Большая проблема с реализацией функций высшего порядка в C заключается в том, что для выполнения чего-либо нетривиального вам нужны замыкания, которые являются указателями на функции. дополнены структурами данных, содержащими локальные переменные, к которым у них есть доступ. Поскольку вся идея замыканий состоит в том, чтобы захватить локальные переменные и передать их вместе с указателем на функцию, без поддержки компилятора обойтись сложно. И даже с поддержкой компилятора трудно обойтись без сборки мусора, потому что переменные могут существовать за пределами своей области видимости, что затрудняет определение того, когда их освободить.

7
ответ дан 30 November 2019 в 11:26
поделиться

Это очень сложно сделать на прямом C. Это более возможно в C ++ (см. учебник по функторам или привязку Boost ] и функции библиотеки). Наконец, C ++ 0x добавляет встроенную поддержку лямбда-функций , которая заботится о том, чтобы вы захватили в закрытие все переменные, от которых зависит ваша функция.

1
ответ дан 30 November 2019 в 11:26
поделиться

В прямом c это действительно делается только с помощью указателей на функции, которые и являются проблемой, и не предназначены для этого типа вещей (отчасти поэтому они боль). Тем не менее, блоки (или замыкания, по мнению сторонних разработчиков) отлично подходят для этого. Они компилируются в gcc-4.x или что-то в этом роде, и в icc что-то, но независимо от того, что вы ищете.К сожалению, я не могу найти никаких хороших руководств в Интернете, но достаточно сказать, что он работает примерно так:

void iterate(char *str, int count, (^block)(str *)){
  for(int i = 0; i < count; i++){
    block(list[i]);
  }
}

main() {
  char str[20];
  iterate(str, 20, ^(char c){
    printf("%c ", c);
  });

  int accum = 0;
  iterate(someList, 20, ^(char c){
    accum += c;
    iterate(str, 20, ^(char c){
      printf("%c ", c);
    });
  });
}

очевидно, что этот код бессмыслен, но он печатает каждый символ строки (str) с пробелом между он затем складывает все символы вместе в аккумулятор и каждый раз, когда это делает, снова распечатывает список символов.

Надеюсь, это поможет. Кстати, блоки очень хорошо видны в api-е Mac OS X Snow Leopard, и я считаю, что они находятся в готовящемся стандарте C ++ 0x, так что на самом деле они не такие уж необычные.

4
ответ дан 30 November 2019 в 11:26
поделиться

Если вы хотите создавать функции высшего порядка, не используйте C. Есть C решения вашей проблемы. Они могут быть не изящными или более элегантными, чем вы думаете.

[Edit] Я предположил, что единственный способ добиться этого - использовать язык сценариев. Другие меня об этом кричали. Итак, я заменяю это предложение следующим: [/ Edit]

Чего вы пытаетесь достичь? Если вы хотите имитировать замыкания, используйте язык, который их поддерживает (вы можете подключиться к Ruby, lua, javascript и т. Д. Через библиотеки). Если вы хотите использовать обратные вызовы, указатели на функции в порядке. Указатели на функции объединяют наиболее опасные области C (указатели и слабую систему типов), поэтому будьте осторожны. Объявления указателей функций тоже неинтересно читать.

Вы можете встретить некоторые библиотеки C, использующие указатели на функции, потому что они должны это делать. Если вы пишете библиотеку, возможно, вам тоже нужно их использовать. Если вы просто используете их в своем собственном коде, вы, вероятно, думаете не на C. Вы думаете шепелявым, или схемой, или ruby, или ... и пытаетесь написать это на C. Изучите способ C.

0
ответ дан 30 November 2019 в 11:26
поделиться

Технически функции более высокого порядка — это просто функции, которые принимают или возвращают функции. Таким образом, такие вещи, как qsort, уже имеют более высокий порядок.

Если вы имеете в виду что-то более похожее на лямбда-функции, найденные в функциональных языках (где функции более высокого порядка действительно становятся полезными), они немного сложнее и не могут быть выполнены естественным образом в текущем стандарте C. Они просто не являются частью языка. Расширение блоков Apple является лучшим кандидатом. Он работает только в GCC (и компиляторе C LLVM), но они действительно полезны. Надеюсь, что-то подобное приживет популярность. Вот несколько соответствующих ресурсов:

19
ответ дан 30 November 2019 в 11:26
поделиться

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

3
ответ дан 30 November 2019 в 11:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: