2024 Clojure 状态调查! 中分享您的看法。

欢迎!请参阅 关于 页面,了解更多关于这里工作方式的信息。

0
Clojure

以下是否为已知行为?很想知道这是为什么。一个直觉告诉我,在字节码级别,recur 只是一个循环/跳转,所以代码更改不会被反射

(defn x
  []
  (recur))

(future (x))

(defn x
  []
  (println "reloaded")
  (recur)) ;; changes in fn (print statement) after reloading x does not get reflected in the recur variant which is still executing

(defn y
  []
  (y))

(future (y))

(defn y
  []
  (println "reloaded")
  (y)) ;; changes get reflected now

2 答案

0

选为最佳答案
 
最佳答案

clj-java-decompiler 显示对于函数 x 基本上是这个

public static Object invokeStatic() {
    while (true) {}
}

和对于 y 是这个

public static final Var const__0;

public static Object invokeStatic() {
    return ((IFn)const__0.getRawRoot()).invoke();
}

这就是 recur 的作用,用于优化自我尾递归。属性 y 在某个时候会耗尽堆栈空间,所以是的,recur 不能动态重新绑定。

0

您可以使用变量来得到期望的结果。

(defn z 
  [idx]
  (prn [:z idx])
  (Thread/sleep 1000)
  (#'z (inc idx)))
(future (z 0))
;; [:z 0]
;; [:z 1]
;; [:z 2]
(defn z 
  [idx]
  (prn [:z :changed idx])
  (Thread/sleep 1000)
  (#'z (inc idx)))
;; [:z :changed 3]
;; [:z :changed 4]

"在 java",它将这样做

public static Object invokeStatic(Object idx) {
    prn(["z", idx ]);
    return ((IFn) RT.read("user/z")).invoke(idx + 1);
}
...