无法在Clojure中更改/建立根绑定:[some-def]和set

Ert*_*tin 6 lisp functional-programming clojure clojurescript

我无法将动态var的值设置为新值.

(def *pop* true)

(set! *pop* false)

=> IllegalStateException Can't change/establish root binding of: *pop* with set  clojure.lang.Var.set (Var.java:221)
Run Code Online (Sandbox Code Playgroud)


我也补充说^:dynamic,这也没用.

(def ^:dynamic *pop* true)

(set! *pop* false)

=> IllegalStateException Can't change/establish root binding of: *pop* with set  clojure.lang.Var.set (Var.java:221)
Run Code Online (Sandbox Code Playgroud)


但另一方面,这段代码有效,(clojure core的var - > *warn-on-reflection*)

(set! *warn-on-reflection* true)
=> true

*warn-on-reflection*
=> true

(set! *warn-on-reflection* false)
=> false

*warn-on-reflection*
=> false
Run Code Online (Sandbox Code Playgroud)

Ale*_*ler 9

动态变量只能set!binding范围内.所以只要调用set!*pop*是行不通的-你需要在上面的调用堆栈绑定某处的运行时动态范围.

(def ^:dynamic *pop* true)
(binding [*pop* *pop*]  ;; defaulted to the root binding value
  (set! *pop* false)    ;; ok, because in dynamic binding scope
  (println *pop*))      ;; prints "false" (inside per-thread dynamic binding)
(println *pop*)         ;; prints "true" (root value)
Run Code Online (Sandbox Code Playgroud)

请注意,它的"动态范围"部分意味着binding您可以在其中进行任意嵌套调用,并且仍然可以访问设置和读取每个线程的值*pop*.

关于*warn-on-reflection*,这看起来像特殊行为,但它实际上完全相同,除了从视图中隐藏.REPL本身围绕每个REPL语句的eval创建一个动态绑定范围,其中绑定了一组硬编码的动态变量,其中*warn-on-reflection*一个是动态变量.你可以在这里找到那组绑定.


ymo*_*nad 5

您可以使用alter-var-root更改根变量。

user=> (def *pop* true)
Warning: *pop* not declared dynamic ...
#'user/*pop*

user=> (alter-var-root #'*pop* (constantly false))
false

user=> *pop*
false
Run Code Online (Sandbox Code Playgroud)