Создание библиотеки функций для мутирования произвольных глобальных переменных

StackOverflow https://stackoverflow.com/questions/20353946

  •  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

Почему бы тебе не избавиться от set-global Функция полностью, и если вы хотите, чтобы вся ваша функция имела такой же стиль передачи в глобальной переменной, просто сделайте их все использовать symbol-value Таким образом, любому, кто использует эти функции, не нужно знать, что это делает, а что не требует цитаты перед мировым именем переменной. Намного проще, верно?

Другие советы

Это плохой стиль и пустая трата вашего времени.

  1. push-something эквивалентно cons.

  2. push-cdr является нет Функциональный: он изменяет аргумент на месте или сбои с ошибкой на nil аргумент

Если вы хотите изменить значение глобальной переменной, то используйте setf Явно намного яснее.

Если вы хотите изменить внутренние внутренности глобального значения каким -либо сложным способом, вам может потребоваться написать специальную функцию для этого, но эта функция должна быть агностикой того факта, что она изменяет значение, связанную с глобальной переменной, в отличие от лексическая переменная.

Короче говоря, есть две отдельные ортогональные проблемы - изменение глобальной переменной (используйте setq) и меняющиеся внутренние объекты (быть агностическими его глобальной природой).

Пса Я не уверен, что вы имеете в виду под «setf не изменяет значение глобальной переменной, когда она находится внутри функции», но::

(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top