Как выполнить функцию на заданном месте

У меня есть список, который содержит некоторые символы и значения. Цель состоит в том, чтобы установить слот класса с помощью метода доступа, чей символ предоставляется списком:

(defclass my-class ()
 ((attr :accessor attr)))

(let ((to-call '(attr "some-value"))
      (obj (make-instance 'my-class)))
 (setf `(,(car to-call) obj) (cadr to-call)))

Пробовал через макрос:

(defmacro call-accessor (to-call)
 `(setf (,(car to-call) obj) "some-value"))

(let ((to-call '(attr "some-value"))
      (obj (make-instance 'my-class)))
 (call-accessor to-call))

Что тоже не работает, поскольку to-call — это символ, а не список.

  • eval не работает, так как to-call является лексической переменной;
  • Невозможно сделать let над макросом, чтобы дать ему список;
  • Я пробовал с with-slots и with-accessors, но проблема осталась прежней, потому что они тоже макросы.
  • Я рассмотрел макросы, которые объявляют другой макрос, и символ-макролет тоже.

Как я могу установить слот с помощью аксессора, соответствующего символу в моем списке?

Спасибо.


person Fnifni    schedule 07.02.2019    source источник


Ответы (3)


Вызов функции доступа

Цель состоит в том, чтобы установить слот класса с помощью аксессора

Аксессор — это пара функций. Вы можете получить часть, которая устанавливает значение через FDEFINITION. Имя функции — список (SETF accessor-name ). Это необычно: Common Lisp в этом случае имеет имена функций, которые являются не символами, а списками.

CL-USER 14 > (let ((to-call '(attr "some-value"))
                   (obj (make-instance 'my-class)))
               (funcall (fdefinition `(setf ,(first to-call)))
                        (second to-call)
                        obj)
               (describe obj))

#<MY-CLASS 40200614FB> is a MY-CLASS
ATTR      "some-value"

Использование функции call-accessor:

CL-USER 25 > (let ((to-call '(attr "some-value"))
                   (obj (make-instance 'my-class)))
               (flet ((call-accessor (obj to-call)
                        (funcall (fdefinition `(setf ,(first to-call)))
                                 (second to-call)
                                 obj)))
                 (call-accessor obj to-call)
                 (describe obj)))

#<MY-CLASS 402000220B> is a MY-CLASS
ATTR      "some-value"

используя SETF с APPLY, чтобы скрыть вызов FDEFINITION

Чтобы использовать setf с вычисляемым методом доступа, может потребоваться использовать форму apply и пользовательскую функцию.

Что-то вроде call-accessor естественно было бы функцией, потому что она выполняет поиск во время выполнения и принимает значения. Попытка использовать макрос была бы более полезной, если бы метод доступа был известен во время во время компиляции.

CL-USER 23 > (let ((to-call '(attr "some-value"))
                   (obj (make-instance 'my-class)))
               (flet (((setf my-setter) (new-value object accessor) 
                        (funcall (fdefinition `(setf ,accessor))
                                 new-value
                                 obj)))
                 (flet ((call-accessor (obj to-call)
                          (setf (apply #'my-setter obj (list (first to-call)))
                                (second to-call))))
                   (call-accessor obj to-call)
                   (describe obj))))

#<MY-CLASS 40200009AB> is a MY-CLASS
ATTR      "some-value"

Выбор структуры данных

Я думаю, что можно вычислять функции доступа и тому подобное. Для этого могут быть варианты использования. CLOS был разработан, чтобы быть динамичным и рефлексивным, чтобы позволить эти вещи.

person Rainer Joswig    schedule 08.02.2019

Вы можете использовать setf из slot-value, используя символ имени слота в вашем пара данных:

(let ((to-call '(attr "some-value")))
  (setf (slot-value obj (first to-call)) (second to-call)))

Тем не менее, использование slot-value напрямую обычно имеет смысл только тогда, когда вы спорите с внутренними объектами (например, с методами/комбинациями инициализации экземпляра; или, возможно, вы работаете над каким-то механизмом сериализации).

Если это не так, вы используете объект просто как ассоциативную структуру данных. Вместо этого я бы предложил использовать alist, plist или hash-map.

person Svante    schedule 07.02.2019
comment
Спасибо за ответ. Я пробовал что-то вроде (setf `(slot-value, obj, (car to-call)... (что терпит неудачу), но я не понимаю, как я могу использовать setf of slot-value для решения проблемы. - person Fnifni; 08.02.2019
comment
Обратите внимание, что здесь используется имя слота (а не метод доступа), и случайно/дизайн имя слота и метод доступа совпадают. - person Rainer Joswig; 08.02.2019

Я согласен с тем, что, вероятно, следует использовать альтернативную структуру, такую ​​​​как hash-table. Но чтобы расширить ответ Сванте относительно slot-value, рабочий код просто:

(setf (slot-value obj 'attr) "some-value")
person Jonathan Johansen    schedule 08.02.2019