Как вы, вероятно, знаете, формы формы Lisp обычно обрабатываются снаружи. Вы должны посмотреть на символ в первой позиции самого внешнего гнездования, чтобы понять форму. Этот символ полностью определяет смысл формы.
;; Common Lisp: define a class A derived from B and C
(defclass a (b c)())
;; Common Lisp: define a function of two arguments
(defun a (b c)())
;; add A to the result of calling function B on variable C:
(+ a (b c))
Традиционно диалекты Лиспа делят формы на формы операторов и формы вызова функций. Форма оператора имеет совершенно произвольный смысл, определяемый фрагментом кода, который компилирует или интерпретирует эти функции (например, оценка просто пересчитывается по всем формам аргументов вызова функции, а результирующие значения передаются функции).
С ранней историей Lisp разрешил пользователям писать собственные операторы.Существовали два подхода к этому: интерпретирующие операторы (исторически известные как fexprs
) и компиляция операторов, известных как макросы. Оба основаны на идее функции, которая получает неоценимую форму в качестве аргумента, так что она может реализовать пользовательскую стратегию, тем самым расширяя модель оценки с новыми поведением.
Оператор типа fexpr
просто передается форме во время выполнения вместе с объектом среды, с помощью которого он может искать значения переменных и т. Д. Затем этот оператор просматривает форму и реализует поведение.
Оператор макроса передается форме в момент макрорасширения (что обычно происходит при чтении форм верхнего уровня непосредственно перед их оценкой или компиляцией). Его задача - не интерпретировать поведение формы, а вместо этого переводить ее, создавая код. То есть макрос - это мини-компилятор. (Сгенерированный код может содержать больше макросообщений, а макрорасширитель позаботится об этом, гарантируя, что все макровызывы будут уничтожены.)
Подход fexpr
не срабатывает, скорее всего, потому что он неэффективен. Это в основном делает невозможным компиляцию, тогда как Lisp-хакеры оценивают компиляцию. (Лисп уже был скомпилированным языком уже около 1960 года.) Подход fexpr
также враждебен в отношении лексических сред; он требует fexpr
, который является функцией, чтобы иметь возможность заглянуть в среду привязки переменных формы, в которой он вызывается, что является своего рода нарушением инкапсуляции, которое не допускается лексическими областями.
Макросписание немного сложнее и в некотором смысле менее гибкое, чем fexprs, но поддержка макрокоманды улучшилась в Lisp в 1960-х годах до 70-х годов, чтобы сделать ее максимально приближенной. Макрос первоначально получал всю форму, а затем сам разбирал ее. Макроопределяющая система превратилась во что-то, что обеспечивает макрофункции аргументами, которые получают разбитый синтаксис в легко усваиваемых частях, включая некоторые вложенные аспекты синтаксиса. Был также разработан синтаксис backquote для написания шаблонов кода, что значительно облегчает выражение генерации кода.
Итак, чтобы ответить на ваш вопрос, как я могу написать такие формы самостоятельно? Например, если:
;; Imitation of old-fashioned technique: receive the whole form,
;; extract parts from it and return the translation.
;; Common Lisp defmacro supports this via the &whole keyword
;; in macro lambda lists which lets us have access to the whole form.
;;
;; (Because we are using defmacro, we need to declare arguments "an co &optional al",
;; to make this a three argument macro with an optional third argument, but
;; we don't use those arguments. In ancient lisps, they would not appear:
;; a macro would be a one-argument function, and would have to check the number
;; of arguments itself, to flag bad syntax like (my-if 42) or (my-if).)
;;
(defmacro my-if (&whole if-form an co &optional al)
(let ((antecedent (second if-form)) ;; extract pieces ourselves
(consequent (third if-form)) ;; from whole (my-if ...) form
(alternative (fourth if-form)))
(list 'cond (list antecedent consequent) (list t alternative))))
;; "Modern" version. Use the parsed arguments, and also take advantage of
;; backquote syntax to write the COND with a syntax that looks like the code.
(defmacro my-if (antecedent consequent &optional alternative)
`(cond (,antecedent ,consequent) (t ,alternative))))
Это пример, потому что фитинг первоначально Лисп был только cond
. В «Лиспе» Маккарти не было if
. Этот «синтаксический сахар» был изобретен позже, вероятно, в виде макроса, расширяющегося до cond
, как и в случае my-if
.
Возможный дубликат [Когда использовать цитату в Lisp] (http://stackoverflow.com/questions/134887/when-to-use-quote-in-lisp) – sds