À la suite de la discussion ici , je me demande si vous pouvez apprendre la programmation fonctionnelle en C?
À la suite de la discussion ici , je me demande si vous pouvez apprendre la programmation fonctionnelle en C?
Réponses:
É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:
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.
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/
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.
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.
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 a
et comptons les b
collections disjointes. Le point de l'exemple est que les variables x
sont capturées par la fermeture définissant la counter
fermeture et chaque fois qu'une nouvelle counter
fermeture is instantiated by the function, it gets its fresh own idea of what
x` 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 syslog
mise en œuvre d'une fonction
var log = function(priority, message) {
…
};
où les arguments priority
et message
devraient ê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 for
boucles 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.
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.
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.
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.