Common Lisp Lisp-1 macro
Я пытаюсь эмулировать единое пространство имен схемы внутри общего lisp с помощью макроса (основанного на Дуге Хойте), который расширяется до лямбды, где каждое использование f!
символ (похож на Дуга Хойта o!
а также g!
символы) в позиции функции расширяется до того же выражения, но с funcall
добавлено в положение функции каждого вызова. Например:
(fplambda (f!z x) (f!z x x))
будет расширяться до:
(LAMBDA (F!Z X) (FUNCALL F!Z X X))
Макрос в настоящее время выглядит так:
(defmacro fplambda (parms &body body)
(let ((syms (remove-duplicates
(remove-if-not #'f!-symbol-p
(flatten body)))))
`(lambda ,parms
(macrolet ,(mapcar
(lambda (f)
`(,f (&rest parmlist) `(funcall ,',f ',@parmlist)))
syms))
,@body)))
но с учетом вышеприведенного ввода, он расширяется (насколько я вижу) до этого:
(LAMBDA (F!F X)
(MACROLET ((F!F (&REST PARMLIST) `(FUNCALL ,'F!F ',@PARMLIST))))
(F!F X X))
В определении макроса F!F не следует заключать в кавычки или не заключать его в кавычки, а parmlist следует просто заключать в кавычки. Что здесь происходит? Заранее спасибо!
1 ответ
Ваше определение в основном верно. Вы только что сделали две довольно простые ошибки. Первый из них был несовпадающим пареном. Макроклет не включает тело (на выходе макрос и тело находятся на одинаковом уровне отступа).
Что касается вложенной обратной цитаты, единственной ошибкой является цитата перед parmlist. Кроме этого все остальное правильно. Запятая и кавычка перед F!F на самом деле правильная. Из гиперспека: "Реализация может интерпретировать форму F1 с кавычками как любую форму F2, которая при оценке даст результат, равный при равенстве, как результат, подразумеваемый вышеприведенным определением". Поскольку внутренняя обратная кавычка еще не была расширена, она не должна быть свободна от кавычек и кавычек. Выражение `(,'x) фактически совпадает с`(x).
Вложенные обратные кавычки общеизвестно сложны. Вероятно, самый простой способ понять их - это прочитать объяснения Стила о них.
Редактировать:
Ответ на ваш вопрос о том, возможно ли использовать выражение fplambda в позиции функции, - нет. Из той части гиперспека, которая касается оценки кода: "Если автомобиль составной формы не является символом, тогда этот автомобиль должен быть лямбда-выражением, и в этом случае составная форма является лямбда-формой". Поскольку машина вида (fplambda ...) не является лямбда-выражением, ваш код больше не является допустимым кодом Common Lisp.
Я нашел способ обойти это, но он уродлив. Вы можете определить макрос для чтения, который позволит вам написать что-то вроде ([fplambda ...] ...) и сделать так, чтобы он читался как
((LAMBDA (&REST #:G1030) (APPLY (FPLAMBDA ...) #:G1030)) ...)
который будет делать то, что вы хотите. Вот код, который позволит вам сделать это:
(set-macro-character #\[ 'bracket-reader)
(set-macro-character #\] (get-macro-character #\)))
(defun bracket-reader (stream char)
"Read in a bracket."
(declare (ignore char))
(let ((gargs (gensym)))
`(lambda (&rest ,gargs)
(apply ,(read-delimited-list #\] stream t)
,gargs))))
Единственное другое решение, которое я могу придумать, - это использовать какой-то код-ходок (я не могу вам помочь).