Почему бы тебе не избавиться от set-global
Функция полностью, и если вы хотите, чтобы вся ваша функция имела такой же стиль передачи в глобальной переменной, просто сделайте их все использовать symbol-value
Таким образом, любому, кто использует эти функции, не нужно знать, что это делает, а что не требует цитаты перед мировым именем переменной. Намного проще, верно?
Создание библиотеки функций для мутирования произвольных глобальных переменных
-
25-08-2022 - |
Вопрос
Обновление: если у меня есть несколько функций, которые я хочу изменить глобальную переменную, которая передается в качестве аргумента функции, некоторые могут сделать это, передавая только символ глобального (как в случае выталкивания чего -либо в часть списка) , но другие функции потребуют, чтобы символ был цитирован при его передаче, чтобы я мог получить доступ к значению символа и мутировать внешнюю переменную, необходимую для использования SetQ в функции. Этот вопрос в основном о создании последовательного интерфейса для пользователя этих функций, не смущая их, что иногда вы передаете символ, в другой момент вы передаете цитируемый символ
Пример способа оптимизации интерфейса для кучи функций, используя помощника, который имеет одинаковое использование без перерыва о том, как работает функция мутации:
Вот 2 основных примера моей техники:
(defun push-something (global something)
(push something global)
global) ;; not necessary to return it here since the
;; preceding line already does, but doing so
;; for consistency with other functions and clarity
(defun push-cdr (global something)
(push something (cdr global))
global) ;; must return it if I am going to set the
;; dynamic var to the result of this function,
;; because the preceding line doesn't return the
;; entire new result of the variable
;;; "dirty" function for mutating global variable using "clean" functions above:
(defun set-global (fn global &rest values)
(setf (symbol-value global) (apply fn (copy-list (eval global)) values)))
В этом последнем я должен eval
а global
так как это цитируется для использования с symbol-value
и затем я copy-list
чтобы global
не случайно не мутировано. fn
Я выбираю (как и в случае с push-cdr
который может быть нетривиальным в более сложных функциях).
Выход:
CL-USER> (defparameter *g2* nil)
*G2*
CL-USER> (set-global #'push-something '*g2* 5)
(5)
CL-USER> *g2*
(5)
CL-USER> (set-global #'push-cdr '*g2* 99)
(5 99)
CL-USER> *g2*
(5 99)
... и те же функции можно использовать с *g1*
или же *g3*
и т.д. на протяжении всей функции доступа set-global
.
Это хороший или плохой стиль, или мне не хватает гораздо лучшего способа достижения этой функции?
Решение 2
Другие советы
Это плохой стиль и пустая трата вашего времени.
push-something
эквивалентноcons
.push-cdr
является нет Функциональный: он изменяет аргумент на месте или сбои с ошибкой наnil
аргумент
Если вы хотите изменить значение глобальной переменной, то используйте setf
Явно намного яснее.
Если вы хотите изменить внутренние внутренности глобального значения каким -либо сложным способом, вам может потребоваться написать специальную функцию для этого, но эта функция должна быть агностикой того факта, что она изменяет значение, связанную с глобальной переменной, в отличие от лексическая переменная.
Короче говоря, есть две отдельные ортогональные проблемы - изменение глобальной переменной (используйте setq
) и меняющиеся внутренние объекты (быть агностическими его глобальной природой).
Пса Я не уверен, что вы имеете в виду под «setf не изменяет значение глобальной переменной, когда она находится внутри функции», но::
(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123