Как я могу сделать setf на аксессоры структуры при использовании интерна - PullRequest
4 голосов
/ 04 сентября 2010

Я бы хотел setf различных полей структуры в зависимости от определенной переменной.Я решил использовать следующий подход:

Создать строку с именем доступа к полю:

(setq my-string (format nil "STRUCT-ESTADISTICAS-NUM-~S" x))

, а затем использовать intern с funcall:

(funcall (intern my-string) *estadisticas*)

Этот вызоввозвращает правильное значение поля структуры, но если я пытаюсь setf изменить это значение, он жалуется, говоря:

(setf (funcall(intern my-string) *estadisticas*) 0)
Error: `(SETF FUNCALL)' is not fbound

Я могу понять, почему это не работает, но я не могу найтиспособ изменить поля структуры.Любая идея?Спасибо.

Ответы [ 2 ]

4 голосов
/ 07 сентября 2010

Мотивация:

Сооружения относятся к объектам сравнительно низкого уровня.«Скорость» была важной целью дизайна.Направление через функции записи не поддерживается стандартом (как я читал).Сегодня используйте CLOS по умолчанию, если только не требуется более высокая эффективность структур (иногда возможно более быстрое чтение и запись слотов со структурами).

Первый стиль:

Не используйте INTERN, используйте FIND-SYMBOL.Также укажите пакет, иначе FIND-SYMBOL будет использовать значение времени выполнения * package * в качестве пакета

Второй - DEFSTRUCT

Если я правильно прочитал стандарт ANSI CLДело не в том, что DEFSTRUCT создает функции записи для слотов, как это делает DEFCLASS.

CL-USER 24 > (defstruct foo bar baz)
FOO

CL-USER 25 > #'(setf foo-bar)

Error: Undefined function (SETF FOO-BAR) in form (FUNCTION (SETF FOO-BAR)).

Итак, создание такого имени (SETF FOO-BAR) и попытка найти для него функцию не удастся, поскольку такая функция не определена DEFSTRUCT.

Thatв пользовательском коде (setf (foo-bar some-struct) 42) работает, основан на определенных расширениях SETF, предоставляемых DEFSTRUCT, но не на определенных функциях доступа SETF.

Некоторые реализации Common Lisp могут предоставлять функции записи какнестандартное расширение к ANSI CL.

Возможные решения :

a) использовать классы CLOS, DEFCLASS делает то, что вы хотите

b) записыватьписатель функционирует сам

(defun (setf foo-bar) (new-value struct)
   (setf (foo-bar struct) new-value))

Теперь:

(funcall (fdefinition '(setf foo-bar)) 300 *foo*)

Выше затем работает.

c) (SETF SLOT-VALUE) - еще одна нестандартная особенность некоторыхреализации.

В некоторых реализациях Common Lisp это работает не только для классов CLOS, но и для структур:

(setf (slot-value some-struct 'bar) 42)

Я не уверен, поддерживает ли Allegro CL это, но этобыло бы легко узнать.

4 голосов
/ 04 сентября 2010

Вы хотите вызвать функцию записи структуры через ее имя, а имя записи - список (setf accessor-name); так что

(funcall (fdefinition (list 'setf (intern my-string))) 0 estadisticas)

Edit:

Не видя остальной части вашего кода, трудно понять, что пошло не так. На SBCL это работает для меня:

(defstruct point x y)
(let ((point (make-point :x 1 :y 2)))
  (funcall (fdefinition (list 'setf (intern "POINT-X"))) 10 point)
  point)

Выше оценивается в

#S(POINT :X 10 :Y 2),

как и ожидалось.

...