Рассмотрим этот вопрос. Здесь основной проблемой является код:
(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))
not'((v1 . val1)(v2 . val2)(v3 . val3))
Таким образом, это рассматривается как код, а не список.
Итак, я застрял здесь. И макросы мне в этом не помогут.
Любая помощь приветствуется.