Pouvez-vous apprendre la programmation fonctionnelle en C? [fermé]

9

À la suite de la discussion ici , je me demande si vous pouvez apprendre la programmation fonctionnelle en C?

sbi
la source
30
Que vous le puissiez ou non, vous ne devriez pas .
R. Martinho Fernandes
27
Absolument! La première étape consiste à écrire un interprète Lisp ;-)
Ferruccio
Si j'ai bien compris, la question aurait dû être d'apprendre différents concepts avec un pseudocode, sans aucun langage réel.
SK-logic
@ SK-logic: Pour faire simple, très peu de programmeurs ont appris la programmation uniquement avec du pseudocode, la plupart ont dû se salir les mains et leurs visages gercés de messages d'erreur du compilateur / interprète.
sbi
4
@sbi, certains des meilleurs programmeurs ont appris la programmation lorsque les compilateurs n'avaient aucun message d'erreur. Le codage sur des cartes perforées nécessite un peu de compréhension de ce que vous faites bien avant d'avoir la possibilité d'exécuter le code. Et inutile de mentionner que la base de la programmation fonctionnelle avait été établie bien avant la construction d'un premier ordinateur.
SK-logic

Réponses:

21

Évidemment, vous pouvez faire de la programmation fonctionnelle en C. En théorie, vous pouvez également apprendre les principes de programmation fonctionnelle en C, mais le langage ne facilite pas les choses.

Je suppose que vous avez au moins un peu d'expérience en POO; si vous le faites, vous devez savoir que la POO peut être effectuée en C, y compris le polymorphisme, les getters / setters, les règles de visibilité, etc. etc., mais c'est assez pénible de le faire, et vous devez connaître à la fois la POO et le C à l'intérieur - pour le retirer. C'est à peu près la même chose avec FP.

Ce que vous devriez faire, c'est d'abord apprendre un langage de programmation fonctionnel (la plupart d'entre eux ont des règles de syntaxe étonnamment simples; ce n'est pas la syntaxe qui les rend difficiles à apprendre), puis laissez votre sagesse nouvellement acquise influencer la façon dont vous écrivez C.


Selon la demande, vous pouvez apprendre quelques choses de FP et ensuite appliquer en, par exemple, C, C ++ ou Java:

  • Évitez l'état, en particulier l'état mutable partagé
  • Appréciez les fonctions pures
  • Appréciez l'évaluation paresseuse
  • Être capable de modéliser en termes de verbes plutôt que de noms
  • Être capable d'aborder les problèmes de manière récursive et itérative
  • Utilisation de fonctions d'ordre supérieur
  • Penser les fonctions comme juste un autre type de valeur, que vous pouvez faire circuler et combiner avec d'autres valeurs
  • Utilisation de fonctions de première classe comme alternative au polymorphisme basé sur les objets
tdammers
la source
1
Pouvez-vous fournir des exemples spécifiques de la façon dont les programmeurs C / C ++ / Java peuvent bénéficier de la sagesse LISP. C'est logique en théorie, mais je cherche quelque chose de concret.
Job
@Job, quel avantage concret peut-il y avoir? Cela élargit leur esprit et leur fait peut-être penser que l'état mutable excessif est une mauvaise chose, que demander de plus?
dan_waterworth
Alors, puis-je en conclure que, s'il est possible d'apprendre (certains) la PF en C, cela n'a aucun sens de le faire?
sbi
@Job: J'ai appris la PF lorsque j'ai appris LISP en tant qu'étudiant il y a de nombreuses années. Environ une décennie plus tard, j'ai appliqué la FP à la méta-programmation de modèles.
sbi
1
@sbi, ma façon préférée d'apprendre de nouveaux langages et concepts est de les implémenter. Et C est un langage assez décent pour implémenter un compilateur. Donc, oui, vous pouvez apprendre la FP avec C.
SK-logic
11

C peut être piraté pour offrir quelques concepts fonctionnels:

Cette question StackOverflow vous en dira plus. Mais bien qu'il semble possible de faire de la programmation fonctionnelle (ou un grand sous-ensemble de) en C, les hacks et les extensions du compilateur et tout ce qui n'est pas la meilleure façon d'apprendre un concept.

Pour réellement apprendre la programmation fonctionnelle, votre meilleur pari est l'un des principaux langages de programmation fonctionnelle comme Lisp et ses dialectes ( Clojure , Scheme ), Erlang et Haskell . N'importe lequel d'entre eux sont des outils parfaits qui fonctionnent dans l'esprit de programmation fonctionnelle. F # est également un bon candidat si vous avez une expérience .Net, mais c'est un langage multi paradigme, pas strictement un langage de programmation fonctionnel.


Comme le note tdammers dans les commentaires:

En fait, LISP, clojure et schéma sont également multi-paradigmes; Haskell, tout en étant pur et paresseux, permet également une programmation impérative dans un contexte monadique, et il prend en charge de manière approfondie le traitement simultané. Tous ont des mécanismes qui mettent en œuvre une grande partie de la sagesse recueillie dans le monde de la POO - encapsulation, héritage, responsabilité unique, composition, etc. Il ne s'agit pas tant de savoir si un langage PERMET d'autres paradigmes; il s'agit de savoir quel paradigme forme le point de départ d'une langue.

À ma connaissance, Lisp et ses dialectes et Erlang sont de meilleurs candidats que F # car ils encouragent la programmation fonctionnelle par rapport à d'autres paradigmes, ce que tdammers déclare magnifiquement comme point de départ d'une langue . F # englobe la programmation fonctionnelle mais ne l'encourage pas par rapport à ses autres paradigmes pris en charge, la programmation impérative et oo.

yannis
la source
Concernant votre dernière phrase: dans ce cas, je dirais que F # est un meilleur candidat car il ne vous piégera pas dans un état d'esprit fonctionnel. Dans un langage multi-paradigme, lorsque vous commencez à marteler des vis, vous pouvez simplement passer à un tournevis. Lorsque vous êtes pris au piège dans un seul paradigme, vous pouvez manquer la différence entre la vis et le clou.
R. Martinho Fernandes
Eh bien, la question est de savoir comment apprendre la programmation fonctionnelle, pas la programmation. Je suppose que l'op a une certaine expérience dans un langage multi paradigme et veut le moyen le plus efficace d'apprendre la programmation fonctionnelle, auquel cas F # est un bon candidat mais pas parfait. Pris au piège dans un seul paradigme est évidemment le meilleur moyen lorsque vous cherchez à en apprendre davantage sur ce paradigme unique, car vous n'avez pas à faire face à tout ce qui ne l'est pas.
yannis
Je crois que l'apprentissage lorsque le paradigme est bien adapté et lorsqu'il est mal adapté à une certaine tâche fait partie de son apprentissage, peut-être le plus important.
R. Martinho Fernandes
4
En fait, LISP, clojure et schéma sont également multi-paradigmes; Haskell, tout en étant pur et paresseux, permet également une programmation impérative dans un contexte monadique, et il prend en charge de manière approfondie le traitement simultané. Tous ces éléments ont des mécanismes qui mettent en œuvre une grande partie de la sagesse recueillie dans le monde de la POO - encapsulation, héritage, responsabilité unique, composition, etc. Il ne s'agit pas tant de savoir si un langage PERMET d'autres paradigmes; il s'agit de savoir quel paradigme constitue le point de départ d'une langue.
tdammers
2
@MartinhoFernandes: On pourrait dire que le fait d'être piégé dans un seul paradigme est le moyen idéal pour apprendre quand c'est vraiment une douleur dans le cul :-)
Jörg W Mittag
2

Vous ne pouvez pas apprendre tous les aspects de la programmation fonctionnelle en C. Mais vous pouvez sûrement commencer la programmation de style fonctionnel avec n'importe quel langage impératif. Ces bits de départ sont- "Comment garder les choses pures pendant la programmation." Et cela peut être fait C aussi. Consultez cet article de blog pour plus de détails -

http://www.johndcook.com/blog/2011/07/24/get-started-functional-programming/

Gulshan
la source
2

TL; DR

La programmation fonctionnelle concerne les fermetures et leurs applications. À moins que quelqu'un ne puisse vous montrer une bibliothèque de fermeture de descente pour C, oubliez d'utiliser C pour apprendre la programmation fonctionnelle.

Qu'est-ce que la programmation fonctionnelle?

Le concept cardinal de la programmation fonctionnelle est la notion de fermetures qui, grosso modo, capture une fonction avec des liaisons de variables. Outre l'utilisation généralisée des fermetures, il existe quelques autres traits distinctifs dans la programmation fonctionnelle, comme l'utilisation de fonctions récursives et de valeurs immuables (les deux jouent bien ensemble). Ces traits sont plus un problème culturel qu'autre chose, et il n'y a pas d'obstacle technique pour les utiliser dans pratiquement toutes les langues, c'est pourquoi je me concentre sur les fermetures dans ma réponse: toutes les langues ne permettent pas de créer facilement des fermetures.

Trois illustrations de l'utilité des fermetures

Une utilisation typique des fermetures est la mise en œuvre de mécanismes de confidentialité. Par exemple, le code Javascript - dans les exemples, j'ai choisi Javascript parce que c'est un langage fonctionnel avec une soi-disant «syntaxe de type C» et votre question suggère que vous êtes familier avec C:

create_counter = function()
{
  var x = 0;
  var counter = function()
  {
    ++x;
    return x;
  };
  return counter;
}

Puis avec

a = create_counter();
b = create_counter();

nous avons deux fonctions aet comptons les bcollections disjointes. Le point de l'exemple est que les variables xsont capturées par la fermeture définissant la counterfermeture et chaque fois qu'une nouvelle counterfermeture is instantiated by the function, it gets its fresh own idea of whatx` l'est.

Une autre utilisation typique des fermetures est la définition d'applications partielles de fonctions. Supposons que nous avons une fonction de reporting similaire à la syslogmise en œuvre d'une fonction

var log = function(priority, message) {

};

où les arguments priorityet messagedevraient être des chaînes, le premier étant l' un "debug", "info"et ainsi de suite. Nous pouvons définir une fabrique de journaux comme celle-ci:

var logWithPriority = function(priority) {
  return function(message) {
    log(priority, message);
  };
};

et l'utiliser pour définir des versions spécialisées de notre fonction de journalisation:

var debug = logWithPriority("debug");
var info = logWithPriority("info");

C'est très utile, car au lieu d'écrire des forboucles sujettes aux erreurs comme celle-ci

for(i = 0; i < journal.length; ++i) {
   log("info", journal[i]);
}

on peut écrire le plus propre, le plus court et le plus simple (il n'y en a pas i, c'est bien mieux):

journal.forEach(logWithPriority("info"));

Un troisième champ d'application important des fermetures est la mise en œuvre de l'évaluation paresseuse - notez que la prise en charge d'un langage spécial peut permettre une meilleure mise en œuvre.

Une fonction paresseuse, au lieu d'effectuer un calcul simple, renvoie une fermeture qui peut être appelée (ou «forcée» dans le jargon de la paresse) pour effectuer la question. La motivation pour ce faire est qu'il sépare la préparation d'un calcul et l'exécution d'un calcul. Un exemple pratique de ceci est la compilation d'expressions régulières: si un programme compile beaucoup d'expressions régulières au démarrage, il aura besoin de beaucoup de temps pour démarrer. Si au lieu de cela nous compilons paresseusement les expressions régulières et les forçons comme nous en avons besoin, alors notre programme peut démarrer rapidement. Bien sûr, les expressions régulières peuvent être remplacées ici par toute structure nécessitant un temps d'initialisation considérable.

Voici comment implémenter une évaluation paresseuse avec des fermetures. Considérons l'implémentation classique de la fonction arrayMax retournant le max dans un tableau:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  };
}

La variante paresseuse serait:

function arrayMax(array) {
  var memo = null;
  function actuallyCompute() {
    if(memo === null) {
      memo = array.reduce(function(a, b) {
        return Math.min(a, b);
      });
    }
    return memo;
  }
  return actuallyCompute;
}

La valeur renvoyée est une fermeture qui peut être utilisée pour calculer la valeur ou la récupérer une autre fois si elle a déjà été calculée.

Avec ces trois exemples, nous devons être convaincus que les fermetures et leurs applications sont au cœur de la programmation fonctionnelle.

Conclusion

Apprendre la programmation fonctionnelle signifie apprendre à programmer avec des fermetures. En conséquence, les langages permettant la manipulation aisée des fermetures, et notamment l'application partielle de fonctions, doivent être pris en compte lors de la recherche d'un langage pour étudier la programmation fonctionnelle. Inversement, les langues où les fermetures ne peuvent pas être facilement manipulées seraient de mauvais choix.

Michael Le Barbier Grünewald
la source
1
Merci pour ce bel échantillon. BTW, comme vous définissez var info, ne serait-ce pas journal.forEach (info)?
ejaenv
Oui, ce serait une variante appropriée! :)
Michael Le Barbier Grünewald
1

Je pense que les outils que vous utilisez influencent beaucoup votre apprentissage. Il est presque impossible d'apprendre des concepts de programmation pour lesquels le langage de programmation que vous utilisez ne fournit pas les moyens de l'utiliser. Bien sûr, vous pouvez toujours apprendre quelques choses, mais vous ne pouvez pas l'apprendre correctement.

Mais c'est de toute façon académique, car, comme Martinho le dit dans son commentaire , même si vous pouviez apprendre la programmation fonctionnelle, vous ne devriez pas essayer de le faire, car il y a des langages où c'est beaucoup plus facile.

sbi
la source
1

Vous ne devez pas apprendre la programmation fonctionnelle en C, mais dans un langage fonctionnel strict (Haskell, Caml, Erlang, etc.).

Si vous êtes novice dans le fonctionnel, vous ne l'aurez jamais vraiment avec un langage non fonctionnel. Plus probablement, vous vous entraînerez à faire ce que vous pensez être une programmation fonctionnelle et apprendrez les choses de la mauvaise façon. Et il est toujours plus difficile de «réapprendre» les choses de la bonne façon que de les avoir apprises de la bonne façon au début.

Quoi qu'il en soit, je pense que faire fonctionnel en C est un bon exercice pour quelqu'un qui sait déjà fonctionnel. Parce que cette personne apprendra ce qui se passe derrière le capot - ce que l'ordinateur fait vraiment.

deadalnix
la source