取り除いてみませんか set-global
完全に機能し、すべての関数をグローバル変数を同じスタイルに渡す必要がある場合は、それらをすべて使用させるだけです symbol-value
したがって、これらの関数を使用している人は誰でも、どのdoと、グローバル変数名の前で見積もりを必要としないかを知る必要はありません。ずっと簡単ですよね?
任意のグローバル変数を変異させる機能のライブラリを作成する
-
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)))
この最後の1つでは、私はしなければなりません 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
明示的にはるかに明確です。
複雑な方法でグローバル価値の内部を変更したい場合は、そのために特別な関数を書く必要があるかもしれませんが、その機能は、それがグローバル変数にバインドされた値を変更しているという事実の不可知論者でなければなりません。語彙変数。
要するに、グローバル変数の変更(使用)の2つの別々の直交問題があります setq
)およびオブジェクトの内部の変化(そのグローバルな性質の不可知論者になる)。
詩「setfが関数内にあるときにグローバル変数の値を変更しない」という意味がわかりませんが、:
(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123