Средства доступа к слотам CLOS: чтение, но не запись

У меня есть список имен слотов объекта CLOS:

(DEFCLASS TRIAL-DATA (STANDARD-OBJECT) 
 ((A-DATUM :ACCESSOR A-DATUM :INITARG :A-DATUM :INITFORM NIL) 
  (BOTH-DATA :ACCESSOR BOTH-DATA :INITARG :BOTH-DATA :INITFORM 0) 
  (CUMULATIVE-DATA :ACCESSOR CUMULATIVE-DATA :INITARG :CUMULATIVE-DATA :INITFORM NIL) 
  (NAME :ACCESSOR NAME :INITARG :NAME :INITFORM VALUE)))

(let* ((td (make-instance 'trial-data))
   (slot-lst (mapcar #'slot-definition-name (class-slots (class-of td)))))

Я могу прочитать значения этих слотов:

(let* ((td (make-instance 'trial-data))
   (slot-lst (mapcar #'slot-definition-name (class-slots (class-of td)))))
(funcall (symbol-function (nth 0 slot-lst)) td))

==> НОЛЬ

Но почему я не могу записать в эти слоты новые значения? Разве мое определение класса пробных данных не должно было создавать функцию доступа для каждого слота?

;; Should set the first slot, a-datum's, value to 42
(let* ((td (make-instance 'trial-data))
       (slot-lst (mapcar #'slot-definition-name (class-slots (class-of td)))))
    (setf (funcall (symbol-function (nth 0 slot-lst)) td) 42))

==>

;Compiler warnings for "/Users/frank/Documents/NRL/Error/Patrolbot/Patrol Construction Notes & Testing.lisp" :
;   In an anonymous lambda form at position 123: Undefined function (SETF FUNCALL)
> Error: Undefined function (SETF FUNCALL) called with arguments (42 #<STANDARD-GENERIC-FUNCTION A-DATUM #x302001D1C5DF> #<TRIAL-DATA #x30200200D95D>) .
> While executing: #<Anonymous Function #x30200200EB7F>, in process Listener-2(5).

person fpt    schedule 20.06.2014    source источник


Ответы (2)


Ответ Райнера Джосвигса касается вопроса, почему вы не можете установить код, который у вас есть сейчас. Однако также важно отметить, что нет никаких причин, по которым имя модуля чтения, записи или доступа должно совпадать с именем слота, поэтому, если вы действительно получили имя слота, вам следует использовать с ним (setf slot-value). Например.,

(defclass foo ()
  ((bar :accessor getbar :initform 42)))

(defparameter *foo* (make-instance 'foo))
;; neither of these work
(setf (bar *foo*) 34)
(funcall #'(setf bar) 34 *foo*)

(slot-value *foo* 'bar)
;=> 42

(setf (slot-value *foo* 'bar) 36)
;=> 26

(slot-value *foo* 'bar)
;=> 36
person Joshua Taylor    schedule 20.06.2014
comment
Таким образом, вы можете использовать (mapcar #'slot-definition-name (class-slots (class-of td))) вместе с (setf slot-value) и читать/записывать данные слотов по индексу. - person Mark Karpov; 21.06.2014

Аксессор называется a-datum.

Читатель:

CL-USER 9 > #'a-datum
#<STANDARD-GENERIC-FUNCTION A-DATUM 406000091C>

Писатель:

CL-USER 10 > #'(setf a-datum)
#<STANDARD-GENERIC-FUNCTION (SETF A-DATUM) 422000958C>

Если вы хотите вызвать через funcall писателя, вам нужно вызвать вышеуказанную функцию.

Если у вас есть простая форма (setf (a-datum foo) 'bar)), то это необходимо решить во время раскрытия макроса.

В сообщении об ошибке говорится, что #'(setf funcall) не определено. Таким образом, (setf (funcall ...) ...) не существует.

Как вы получаете функцию записи в вашем случае?

CL-USER 11 > (fdefinition '(setf a-datum))
#<STANDARD-GENERIC-FUNCTION (SETF A-DATUM) 422000958C>

CL-USER 12 > (let ((name 'a-datum)) (fdefinition `(setf ,name)))
#<STANDARD-GENERIC-FUNCTION (SETF A-DATUM) 422000958C>

Задача для вас: каковы правильные аргументы для вышеуказанной функции?

person Rainer Joswig    schedule 20.06.2014