Как я могу сделать 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 это, но это было бы легко выяснить.