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);
}
...