Как я могу сделать setf на средства доступа структуры при использовании интерна

Я бы хотел 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 ответа

Решение

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

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

Редактировать:

Не видя остальной части вашего кода, трудно понять, что пошло не так. На 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),

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

Мотивация:

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

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

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

Второе - УНИЧТОЖЕНИЕ

Если я правильно прочитал стандарт 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.

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

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

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

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

б) написать функции писателя самостоятельно

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

Сейчас:

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

Выше тогда работает.

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

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

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

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

Другие вопросы по тегам