Ни функция, ни макрос не подойдут
Задумайтесь над этим вопросом. Здесь основной проблемой является код:
(progv '(op arg) '(1+ 1)
(eval '(op arg)))
Проблема здесь в том, что progv
привязывает значение к переменной как переменную symbol-value
не symbol-function
, Но это очевидно, потому что мы не предложили явно, какие значения являются функциями.
План
Итак, чтобы решить эту проблему, я подумал о том, чтобы вручную динамически связывать переменные с их значениями в зависимости от типа значений. Если значения fboundp
тогда они должны быть связаны с symbol-function
переменной. Ограничение в том, что match-if
не может быть macro
, Это должно быть function
потому что это называется funcall
,
Макрос:functioner
:
(defmacro functioner (var val)
`(if (and (symbolp ',val)
(fboundp ',val))
(setf (symbol-function ',var) #',val)
(setf ,var ,val)))
Функция:match-if
:
(defun match-if (pattern input bindings)
(eval `(and (let ,(mapcar #'(lambda (x) (list (car x))) bindings)
(declare (special ,@ (mapcar #'car bindings)))
(loop for i in ',bindings
do (eval `(functioner ,(first i) ,(rest i))))
(eval (second (first ,pattern))))
(pat-match (rest ,pattern) ,input ,bindings))))
Здесь let
Часть объявляет все переменные лексически (предположительно). затем declare
объявляет их special
, затем functioner
удачно связывает переменные и их значения. Затем код в шаблоне оценивается. Если часть кода истинна, то только функция сопоставления с образцом pat-match
вызывается.
Эта проблема
Проблема в том, что в функции оцениваются все ее аргументы. таким образом bindings
в let
а также declare
запчасти будут заменены на что-то вроде:((v1 . val1)(v2 . val2)(v3 . val3))
не'((v1 . val1)(v2 . val2)(v3 . val3))
Таким образом, это рассматривается как код, а не как список.
Итак, я застрял здесь. И макросы не помогут мне в этом.
Любая помощь приветствуется.
1 ответ
Не ответ, который вы ищете, но PROGV
специальный оператор; ему предоставляется возможность изменять динамические привязки переменных во время выполнения; AFAIK, вы не можете просто взломать его для работы с "динамическими привязками функций". Точка progv
заключается в использовании списка символов и значений, которые оцениваются, что означает, что вы можете генерировать символы во время выполнения и динамически связывать их с соответствующими значениями.
Вы можете найти решение с eval
но учтите, что если вы макрорасширитесь в (eval ...)
затем вы теряете окружающий лексический контекст, который обычно не тот, который вы хотите ("eval" работает в нулевой лексической среде). Я предполагаю, что у вас также может быть пользовательский обходчик кода, который работает с формами верхнего уровня, но реорганизует их, когда находит ваш специальный оператор, чтобы вернуть контекст обратно, производя что-то вроде (eval '(let (...) ...))
,