Переназначение глобальной переменной внутри функции без передачи имени переменной - PullRequest
0 голосов
/ 22 мая 2018

Как описано в заголовке, я пытаюсь решить следующую проблему:

(setq s ())

(defun reassign (val)
  (setq val 10))

(reassign s)

(print s)
-> Output: s = nil

Я хочу, чтобы reassign деструктивно присвоил s = 10.Есть ли простой способ справиться с этим, не используя имя переменной s внутри функции и не меняя только функцию?(Могут ли быть включены макросы?) Буду благодарен за любые советы!:)

Ответы [ 2 ]

0 голосов
/ 22 мая 2018
(defun reassign (val)
  (setq val 10))

(reassign s)

При вызове (reassign s) значение s передается в reassign, где оно локально связано с val.В вашем случае это будет nil, если вы уже объявили s с DEFVAR перед тем, как установить его на () (см. setq и defvar в Лиспе ).

Внутри reassign вызов SETQ изменяет локальную привязку.

Глобальная привязка

Каждый символ может содержать глобальное значение.Если вы хотите изменить ячейку значения символа, используйте метод доступа SYMBOL-VALUE:

(setf (symbol-value 's) 10)

Обратите внимание, как указывается s.Вы изменяете не символ, в настоящее время связанный с s (который будет nil, постоянная переменная), а сам символ s.(SETF SYMBOL) похоже на прямой вызов SET.

Лексическое и динамическое связывание

Если, однако, вы хотите изменить place и, в частности, привязки лексических и динамических переменных, необходимо определить макрос:

(defmacro reassign (place)
  `(setf ,place 10))

SETF расширяется до кода, необходимого для обновления места.Вы также можете указать (gethash key table) вместо переменной без кавычек, которая затем обновит содержимое таблицы.

В случае локальных переменных код, который вызывает reassignв конечном итоге расширится до вызова специального оператора SETQ, который знает, как изменить лексические привязки (он также обрабатывает SYMBOL-MACROLET привязок).

0 голосов
/ 22 мая 2018

Да, вы правильно догадались.вам нужен макрос.

(defmacro reassign (var &optional (val 10)) `(setq ,var ,val))

(defvar s ())   ;; @Svante remarked that setq can be dangerous to create a variable
s ;; NIL
(reassign s)
s ;; 10

;; the `&optional (val 10)` makes the value optional and 10 to the 
;; default value of val if not given.

В вашем примере

(defun reassign (val) (setq val 10))

val - это первый аргумент специальной формы setq: val в setq не становится s, хотя вы дали reassign для val.Он остается val, поэтому вы назначаете 10 в функциональной области на val.Вы можете сделать это видимым:

(setq s ())

(defun reassign (val)
  (print "You gave for `val`:")
  (print val) 
  (setq val 10)
  (print "The form assigned 10 literally to val")
  (print "Proof: Print out val in this scope:")
  (print val))

(reassign s)

;; 
;; "You gave for `val`:" 
;; NIL 
;; "The form assigned 10 literally to val" 
;; "Proof: Print out val in this scope:" 
;; 10 
;; 10

(print val)

*** - SYSTEM::READ-EVAL-PRINT: variable VAL has no value
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of VAL.
STORE-VALUE    :R2      Input a new value for VAL.
ABORT          :R3      Abort main loop
;; since val has not been initiated before

Кроме того, setq функции выполняется в пределах функциональной области.Именно поэтому вне функции val сохраняется старое значение.

(defvar val ()) ;; NIL
(print val)   ;; NIL

(defun reassign (val)
  (print "You gave for `val`:")
  (print val) 
  (setq val 10)
  (print "The form assigned 10 literally to val")
  (print "Proof: Print out val in this scope:")
  (print val))

(reassign 'whatever) ;; inside function val becomes 10
;;
;;"You gave for `val`:" 
;;WHATEVER 
;;"The form assigned 10 literally to val" 
;;"Proof: Print out val in this scope:" 
;;10 ;; val becomes indeed 10 until leaving function 
;;10

;; but retains old value after leaving the function
(print val)
;;
;; NIL
;; NIL

Макрос, напротив, заменяет вызов макроса (reassign s) на форму (setq s 10).Поэтому при выполнении переназначение происходит в среде, в которой мы определили (defvar s ()).Поэтому после переназначения s сохраняет новое присвоенное значение, поскольку оно было переназначено в рабочей среде.

...