Как выполнить функцию на заданном месте - PullRequest
0 голосов
/ 08 февраля 2019

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

(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, но проблема остается той же, потому чтоони также являются макросами.
  • Я рассмотрел макросы, которые объявляют другие макросы, и символ-макрослет тоже.

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

Спасибо.

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

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

(setf (slot-value obj 'attr) "some-value")
0 голосов
/ 08 февраля 2019

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

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

Аксессором является пара функций.Вы можете получить часть, которая устанавливает значение через 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 был разработан, чтобы быть динамичным и отражающим, чтобы позволить эти вещи.

0 голосов
/ 08 февраля 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.

...