Ни функция, ни макрос не подходят

Рассмотрим этот вопрос. Здесь основной проблемой является код:

(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))
Таким образом, это рассматривается как код, а не список.
Итак, я застрял здесь. И макросы мне в этом не помогут.
Любая помощь приветствуется.


person Mooncrater    schedule 23.06.2017    source источник


Ответы (1)


Не тот ответ, который вы ищете, но PROGV — это специальный оператор; предоставляется возможность изменять динамические привязки переменных во время выполнения; Насколько я знаю, вы не можете просто взломать его, чтобы работать с «динамическими привязками функций». Смысл progv заключается в использовании списка символов и значений, которые оцениваются, что означает, что вы можете генерировать символы во время выполнения и динамически привязывать их к соответствующим значениям.

Возможно, вам удастся найти решение с помощью eval, но обратите внимание, что если вы макрорасширяете до (eval ...), вы теряете окружающий лексический контекст, что обычно не то, что вам нужно («eval» работает с нулевым лексическим окружением). Я предполагаю, что у вас также может быть специальный обходчик кода, который работает с формами верхнего уровня, но реорганизует их, когда находит ваш специальный оператор, чтобы вернуть контекст, создавая что-то вроде (eval '(let (...) ...)).

person coredump    schedule 23.06.2017
comment
christophe.rhodes.io/notes/blog/posts/2014/ хорошее начало - person coredump; 24.06.2017
comment
Эта версия match-if работает. Все, что мне нужно было сделать, это добавить кавычки перед ,pattern , ,input и ,bindings. - person Mooncrater; 29.06.2017