33 votes

Programmation fonctionnelle en C avec macro générateurs "Higher Order Function"

Faites attention avec soin, car c'est un enfer d'une question ;-)

Je veux utiliser un modèle de fonctions génériques sont une collection d'actions (comme la recherche, foreach, etc.) en C, tout en maintenant compilateur de vérifier le type statique. Il est assez simple alors que vous êtes en utilisant de simples rappels comme dans cet exemple:

#define MAKE_FOREACH(TYPE)\
void foreach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)) {\
  for(int i = 0; i < n; i++) {\
    f(array[i]);\
  }\
}

ainsi, vous pouvez faire des choses comme:

MAKE_FOREACH(int)
MAKE_FOREACH(float)

void intcallback(int x){
  printf("got %d\n", x);
}

void floatcallback(float x){
  printf("got %f\n", x);
}

int main(){
  int[5] iarray = {1,2,3,4,5};
  float[5] farray = {1.0,2.0,3.0,4.0,5.0};
  foreach_int(iarray, 5, intcallback);
  foreach_float(farray, 5, floatcallback);
}

Si je tiens à mettre en œuvre des rappels avec des types de retour, par exemple pour faire une "carte" de la fonction, j'ai pu faire:

#define MAKE_MAP(TYPE, RTYPE)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE)) {\
  RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
  for(int i = 0; i < n; i++) {\
    result[i]=f(array[i]);\
  }\
}

Pour l'instant, donc bon. Le problème vient maintenant, quand je veux mes fonctions de rappel à accepter n'importe quel nombre de tapé arguments.

L'idée est quelque chose comme:

#define MAKE_MAP(TYPE, RTYPE, ...)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE, __VA_ARGS__), __VA_ARGS__)
/*this would work for the declaration (because just the types would be enough)
but the  parameter names are missing :-s*/ \
{\
  RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
  for(int i = 0; i < n; i++) {\
    result[i]=f(array[i], /*here the names of the parameters, in order*/);\
  }\
}

donc, comme vous pouvez le voir, je pourrais déclarer une fonction map comme:

MAKE_MAP(int, float, char)

donner:

float* map_int(int[n] array, int n, float(*f)(int, char), char);

mais je ne peux pas comprendre comment mettre en œuvre le passage de paramètres avec le préprocesseur. C'est là que je demande votre aide, des idées et des suggestions.

(En passant, ne me dites pas d'utiliser un variadic de la fonction en tant que modèle, et en passant une va_list argument à la fonction de rappel, parce que tout ça était à cause de la vérification de type :-p)

12voto

Nikolai N Fetissov Points 52093

Si vous êtes sous Linux / BSD Unix, jetez un œil à queue (3) et vérifiez dans /usr/include/sys/queue.h - cela a déjà été fait :)

1voto

diapir Points 1017

Une question récente a soulevé pas mal de préjugés éhontés qui abusent des bibliothèques.

1voto

Basile Starynkevitch Points 67055

Pour information, le code source de GCC 4.6 implémente des astuces similaires pour les vecteurs. Regardez dans son fichier gcc/vec.h

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X