web-dev-qa-db-fra.com

Quels sont les outils pour la programmation fonctionnelle en C?

Récemment, j'ai beaucoup réfléchi à la manière de faire de la programmation fonctionnelle en C (not C++). De toute évidence, C est un langage procédural et ne supporte pas vraiment la programmation fonctionnelle de manière native.

Existe-t-il des extensions de compilateur/langage qui ajoutent des constructions de programmation fonctionnelles au langage? GCC fournit des fonctions imbriquées en tant qu'extension de langage; Les fonctions imbriquées peuvent accéder aux variables à partir du cadre de pile parent, mais ceci est encore loin des fermetures matures.

Par exemple, une chose qui pourrait être vraiment utile en C est que partout où un pointeur de fonction est attendu, vous pouvez passer une expression lambda, créant une fermeture qui se décompose en un pointeur de fonction. C++ 0x va inclure les expressions lambda (ce que je trouve génial); Cependant, je cherche des outils applicables au C. droit.

[Éditer] Pour clarifier, je n'essaye pas de résoudre un problème particulier en C qui serait plus adapté à la programmation fonctionnelle; Je suis simplement curieux de savoir quels outils existent si je voulais le faire.

140
Adam Rosenfield

FFCALL vous permet de construire des fermetures en C - callback = alloc_callback(&function, data) renvoie un pointeur de fonction tel que callback(arg1, ...) équivaut à appeler function(data, arg1, ...). Cependant, vous devrez gérer la récupération de place manuellement.

De même, blocks ont été ajoutés à la branche de GCC d'Apple; Ce ne sont pas des pointeurs de fonction, mais ils vous permettent de contourner les lambdas tout en évitant le besoin de construire et de libérer du stockage pour les variables capturées à la main (effectivement, une copie et un comptage des références ont lieu, cachés derrière des bibliothèques syntaxiques de sucre et d'exécution).

38
ephemient

Vous pouvez utiliser les fonctions imbriquées de GCC pour simuler les expressions lambda. En fait, j'ai une macro à faire pour moi:

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

Utilisez comme ceci:

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

La programmation fonctionnelle ne concerne pas les lambdas, il s’agit uniquement de fonctions pures. Ainsi, les éléments suivants encouragent largement le style fonctionnel:

  1. Utilisez uniquement des arguments de fonction, n'utilisez pas l'état global.

  2. Minimiser les effets secondaires, par exemple printf, ou tout autre IO. Renvoie les données décrivant IO qui peuvent être exécutées au lieu de provoquer les effets secondaires directement dans toutes les fonctions. 

Ceci peut être réalisé en clair c, pas besoin de magie.

53
Andy Till

Le livre de Hartel & Muller, Functional C, se trouve actuellement (2012-01-02) sur: http://eprints.eemcs.utwente.nl/1077/ (il existe un lien vers PDF version).

17
FooF

La principale chose qui me vient à l’esprit est l’utilisation de générateurs de code. Seriez-vous prêt à programmer dans un langage différent qui fournisse la programmation fonctionnelle, puis à générer le code C à partir de cela?

Si ce n’est pas une option attrayante, vous pourriez alors abuser du RPC pour obtenir une partie du parcours. Le système de macros devrait vous permettre d’émuler certaines idées de programmation fonctionnelles. J'ai entendu dire que gcc est implémenté de cette façon mais je n'ai jamais vérifié.

C peut bien sûr contourner les fonctions en utilisant des pointeurs de fonction, les problèmes principaux étant le manque de fermetures et le système de types ayant tendance à gêner. Vous pouvez explorer des systèmes macro plus puissants que le CPP, tel que M4. Je suppose qu'en fin de compte, ce que je suggère, c'est que le vrai C ne soit pas à la hauteur de la tâche sans un effort considérable, mais vous pouvez étendre C pour qu'il soit à la hauteur de la tâche. Cette extension ressemblerait le plus à C si vous utilisiez CPP ou vous pouviez aller à l’autre extrémité du spectre et générer du code C à partir d’une autre langue.

7
Jason Dagit

Si vous souhaitez implémenter des clôtures, vous devrez vous familiariser avec le langage d'assemblage et la permutation/gestion des piles. Ne pas recommander contre cela, juste dire que c'est ce que vous devrez faire.

Vous ne savez pas comment vous allez gérer les fonctions anonymes en C? Sur une machine von Neumann, vous pouvez cependant effectuer des fonctions anonymes en asm.

5
Paul Nathan
4
ja.

La condition préalable au style de programmation fonctionnelle est une fonction de première classe . Elle peut être simulée en C portable si vous tolérez ce qui suit:

  • gestion manuelle des liaisons de portée lexicale, alias fermetures.
  • gestion manuelle de la durée de vie des variables de fonction.
  • syntaxe alternative de la fonction application/call.
/* 
 * 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;

la durée d'exécution d'un tel code pourrait être aussi petite que celle ci-dessous

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 substance, nous imitons une fonction de première classe avec des fermetures représentées par une paire de fonctions/arguments plus un groupe de macroses. Le code complet pourrait être trouvé ici .

3
Viktor Shepel

Quelques langages de programmation sont écrits en C. Et certains d’entre eux prennent en charge des citoyens de première classe, les langues de ce domaine sont ecl (embbedabble common LISP IIRC), Gnu Smalltalk (gst) (Smalltalk a des blocs), puis il pour les "fermetures" par exemple dans glib2 http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure Alors peut-être utiliser certaines de ces implémentations pour faire de la programmation fonctionnelle peut être une option. 

Eh bien ou vous pouvez aller apprendre Ocaml, Haskell, Mozart/Oz ou autres ;-)

Cordialement

1
Friedrich

Le langage Felix est compilé en C++. Peut-être que cela pourrait être une pierre angulaire, si le C++ ne vous dérange pas.

1

La façon dont je me suis mis à faire de la programmation fonctionnelle en C a été d’écrire un interpréteur de langage fonctionnel en C. Je l’ai baptisé Fexl, qui signifie «Fonction Expression Language».

L'interprète est très petit, compilant jusqu'à 68K sur mon système avec l'option -O3 activée. Ce n'est pas un jouet non plus - je l'utilise pour tout le nouveau code de production que j'écris pour mon entreprise (comptabilité Web pour les partenariats d'investissement).

Maintenant, j’écris du code C uniquement pour (1) ajouter une fonction intégrée qui appelle une routine système (par exemple, fork, exec, setrlimit, etc.) ou pour une sous-chaîne).

Le mécanisme du module est basé sur le concept de "contexte". Un contexte est une fonction (écrite en Fexl) qui associe un symbole à sa définition. Lorsque vous lisez un fichier Fexl, vous pouvez le résoudre avec le contexte de votre choix. Cela vous permet de créer des environnements personnalisés ou d'exécuter du code dans un "sandbox" restreint.

http://fexl.com

0
Patrick Chkoreff