Il y a beaucoup de langues qui permettent une sorte de métaprogrammation . En particulier, je suis surpris de ne voir aucune réponse parler de la famille de langues Lisp .
De wikipedia:
La métaprogrammation est l'écriture de programmes informatiques avec la capacité de traiter les programmes comme leurs données.
Plus tard dans le texte:
Lisp est probablement le langage par excellence avec les installations de métaprogrammation, à la fois en raison de sa priorité historique et de la simplicité et de la puissance de sa métaprogrammation.
Langues Lisp
Suit une introduction rapide à Lisp.
Une façon de voir le code consiste à suivre une suite d'instructions: faites ceci, puis faites-le, puis procédez comme suit ... Ceci est une liste! Une liste de choses à faire pour le programme. Et bien sûr, vous pouvez avoir des listes dans des listes pour représenter des boucles, etc.
Si nous représentons une liste contenant les éléments a, b, c, d comme celui - ci: (ABCD) nous obtenons quelque chose qui ressemble à un appel de fonction Lisp, où a
est la fonction, et b
, c
, d
sont les arguments. Si fait le typique "Hello World!" programme pourrait être écrit comme suit:(println "Hello World!")
Bien sûr b
, c
ou d
pourrait être des listes qui donnent aussi quelque chose. Ce qui suit: (println "I can add :" (+ 1 3) )
serait alors imprimer "" Je peux ajouter: 4 ".
Ainsi, un programme est une série de listes imbriquées et le premier élément est une fonction. La bonne nouvelle est que nous pouvons manipuler des listes! Nous pouvons donc manipuler les langages de programmation.
L'avantage Lisp
Lisps ne sont pas tant des langages de programmation qu'une boîte à outils permettant de les créer. Un langage de programmation programmable.
Il est non seulement beaucoup plus facile avec Lisps de créer de nouveaux opérateurs, il est également presque impossible d'écrire certains opérateurs dans d'autres langues car les arguments sont évalués lorsqu'ils sont transmis à la fonction.
Par exemple, dans un langage de type C, supposons que vous souhaitiez écrire if
vous-même un opérateur, par exemple:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
Dans ce cas, les deux arguments seront évalués et imprimés, dans un ordre dépendant de l'ordre d'évaluation des arguments.
En Lisps, écrire un opérateur (on appelle ça une macro) et écrire une fonction est à peu près la même chose et utilisé de la même manière. La principale différence est que les paramètres d'une macro ne sont pas évalués avant d'être passés en tant qu'arguments à la macro. Ceci est essentiel pour pouvoir écrire certains opérateurs, comme if
ci - dessus.
Langues du monde réel
Montrer comment est exactement un peu hors de portée ici, mais je vous encourage à essayer de programmer dans un Lisp pour en savoir plus. Par exemple, vous pouvez regarder:
- Scheme , un vieux Lisp assez "pur" avec un petit noyau
- Common Lisp, un Lisp plus grand avec un système objet bien intégré et de nombreuses implémentations (normalisé ANSI)
- Raquette un Lisp dactylographié
- Clojure mon préféré, les exemples ci-dessus étaient du code Clojure. Un Lisp moderne fonctionnant sur la JVM. Il existe également quelques exemples de macros Clojure sur SO (mais ce n’est pas le bon endroit pour commencer. Je commencerais par regarder 4clojure , braveclojure ou clojure koans )).
Oh, au fait, Lisp veut dire LISt Processing.
Concernant vos exemples
Je vais donner des exemples en utilisant Clojure ci-dessous:
Si vous pouvez écrire une add
fonction dans Clojure (defn add [a b] ...your-implementation-here... )
, vous pouvez le nommer +
ainsi (defn + [a b] ...your-implementation-here... )
. C’est en fait ce qui est fait dans l’ implémentation réelle (le corps de la fonction est un peu plus impliqué mais la définition est essentiellement la même que celle que j’ai écrite ci-dessus).
Qu'en est-il de la notation infixe? Eh bien Clojure utilise une prefix
notation (ou polonaise), nous pourrions donc créer une infix-to-prefix
macro qui transformerait le code préfixé en code Clojure. Ce qui est en fait étonnamment facile (c’est en fait l’un des exercices de macro dans les koans du clojure)! On peut également le voir à l'état sauvage, par exemple voir Macro Incanter$=
.
Voici la version la plus simple des koans expliqués:
(defmacro infix [form]
(list (second form) (first form) (nth form 2)))
;; takes a form (ie. some code) as parameter
;; and returns a list (ie. some other code)
;; where the first element is the second element from the original form
;; and the second element is the first element from the original form
;; and the third element is the third element from the original form (indexes start at 0)
;; example :
;; (infix (9 + 1))
;; will become (+ 9 1) which is valid Clojure code and will be executed to give 10 as a result
Pour pousser plus loin le propos, quelques citations de Lisp :
«Ce qui distingue Lisp, c’est qu’il est conçu pour évoluer. Vous pouvez utiliser Lisp pour définir de nouveaux opérateurs Lisp. Au fur et à mesure que de nouvelles abstractions deviennent populaires (programmation orientée objet, par exemple), il s'avère toujours facile de les implémenter dans Lisp. Comme l’ADN, un tel langage ne se démode pas.
- Paul Graham, ANSI Common Lisp
«Programmer en Lisp, c'est comme jouer avec les forces primordiales de l'univers. Il se sent comme un éclair entre vos doigts. Aucune autre langue ne se sent même proche. "
- Glenn Ehrlich, Route de Lisp