La réponse courte: les macros sont utilisées pour la définition de la syntaxe du langage d'extension pour Common Lisp ou Spécifique au Domaine des Langues (Dsl). Ces langues sont incorporés à l'intérieur de votre existant du code Lisp. Maintenant, les DSLs peut avoir une syntaxe semblable à Lisp (comme Peter Norvig du Prologue Interprète pour Common Lisp) ou complètement différente (par exemple, la Notation Infixe Mathématiques pour Clojure).
Comme un exemple plus concret: Python a des interprétations de la liste intégré dans la langue. Cela donne une syntaxe simple pour un cas courant divisibleByTwo = [x for x in range(10) if x % 2 == 0]
donne les nombres de 0 à 9 qui sont divisibles par deux. De retour dans le Python 1.5 jours, il n'y avait pas une telle syntaxe, et qui aurait exprimé comme suit:
divisibleByTwo = []
for x in range( 10 ):
if x % 2 == 0:
divisibleByTwo.append( x )
Ce sont à la fois fonctionnellement équivalent. Nous allons appeler notre suspension de l'incrédulité et de faire semblant de Lisp est très limitée boucle macro qui ne fonctionne tout simplement itération et pas de moyen facile de faire l'équivalent d'interprétations de la liste.
En Lisp, vous pouvez écrire le suivant. Je note cet exemple artificiel est repris à l'identique du code Python pas un bon exemple de code Lisp.
;; the following two functions just make equivalent of Python's range function
;; you can safely ignore them unless you are running this code
(defun range-helper (x)
(if (= x 0)
(list x)
(cons x (range-helper (- x 1)))))
(defun range (x)
(reverse (range-helper (- x 1))))
;; equivalent to the python example:
;; define a variable
(defvar divisibleByTwo nil)
;; loop from 0 upto and including 9
(loop for x in (range 10)
;; test for divisibility by two
if (= (mod x 2) 0)
;; append to the list
do (setq divisibleByTwo (append divisibleByTwo (list x))))
Avant d'aller plus loin: je devrais expliquer un peu de ce qu'une macro est. C'est une transformation de code par le code de code. C'est un morceau de code lu par l'interprète (ou le compilateur) qui prend dans le code comme un argument n'est qu'une manipulation et renvoie le résultat qui est ensuite exécuté en place.
Bien sûr, c'est beaucoup de saisie et de programmeurs sont des paresseux. Donc, nous pourrions définir DSL pour faire des interprétations de la liste. En fait, nous avons déjà à l'aide d'une macro déjà (la boucle de macro).
Lisp définit un couple de syntaxe spéciale formes. L'apostrophe (') indique le prochain jeton est un littéral. Le quasiquote (`) indique le prochain jeton est un littéral avec échappe. Les fuites sont indiqués par l'opérateur virgule. Le littéral '(1 2 3) est l'équivalent de Python [1, 2, 3]. Vous pouvez l'affecter à une autre variable ou de l'utiliser à la place. Vous pouvez penser `(1 2 ,x) comme l'équivalent de Python [1, 2, x] où x est une variable définie précédemment. Cette liste notation est une partie de la magie qui va dans les macros. La deuxième partie est le Lisp lecteur qui intelligemment subtitutes macros pour le code, mais c'est mieux illustré ci-dessous:
Nous pouvons donc définir une macro appelée lcomp
(court pour la compréhension de liste). C'est la syntaxe sera exactement comme le python que nous avons utilisé dans l'exemple [x for x in range(10) if x % 2 == 0]
- (lcomp x for x in (range 10) if (= (% x 2) 0))
(defmacro lcomp (expression for var in list conditional conditional-test)
;; create a unique variable name for the result
(let ((result (gensym)))
;; the arguments are really code so we can substitute them
;; store nil in the unique variable name generated above
`(let ((,result nil))
;; var is a variable name
;; list is the list literal we are suppose to iterate over
(loop for ,var in ,list
;; conditional is if or unless
;; conditioanl-test is (= (mod x 2) 0) in our examples
,conditional ,conditional-test
;; and this is the action from the earlier lisp example
;; result = result + [x] in python
do (setq ,result (append ,result (list ,expression))))
;; return the result
,result)))
Maintenant, nous pouvons exécuter la ligne de commande:
CL-USER> (lcomp x for x in (range 10) if (= (mod x 2) 0))
(0 2 4 6 8)
Très soigné, hein? Maintenant, il ne s'arrête pas là. Vous disposez d'un mécanisme, d'un pinceau. Vous pouvez avoir toute la syntaxe que vous pourriez probablement vouloir. Comme Python ou C#'s avec la syntaxe. Ou .NET de la syntaxe LINQ. En fin de compte, c'est ce qui attire les gens à Lisp - flexibilité ultime.