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

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

0票数
core.async

{quote}
(def ^:dynamic foo 42)

(go

(let (link: old foo)
  (set! foo 45)
  (println old foo)
  (set! foo old)))

{quote}

保留绑定的值为45(与binding+with-redefs的代码相同)。问题在于某种方式下let绑定内联了foo的引用。例如,println语句编译为

{quote}
...
var inst_43089 = cljs.core.println.call(null,full.async.foo,full.async.foo);
...
{quote}

我目前正在查看ioc_macros.clj,但我还没有找到问题所在的部分。任何提示都很有帮助。

8 答案

0票数
_由hiredman发表的评论:

对于好奇的人,上面(在ClojureScript中)的宏展开是清理过的


(let* [c__9201__auto__ (chan 1)]
      (run
        (fn []
          (let [f__9202__auto__ (let [switch__9186__auto__ (fn [state_9258]
                                                             (let [state_val_9259 (aget state_9258 1)]
                                                               (cond
                                                                (== state_val_9259 1) (let [inst_9254 (set! foo 45)
                                                                                            inst_9255 (println foo foo)
                                                                                            inst_9256 (set! foo foo)
                                                                                            state_9258 (aset-all! state_9258 7 inst_9255 8 inst_9254)]
                                                                                            )(return-chan state_9258 inst_9256))))
                                    (fn state-machine__9187__auto__/
                                    ([] (aset-all! (make-array 9) 0 state-machine__9187__auto__/ 1 1))
                                    ([state_9258] (let [ret-value__9188__auto__ (try
                                                                                    (loop []
                                                                                    (let [result__9189__auto__ (switch__9186__auto__ state_9258)]
                                                                                     (                           如果 (keyword-identical? result__9189__auto__ :recur)
                                                                                        (recur)
                                                                                        result__9189__auto__)))
                                                                                    (catch js/Object ex__9190__auto__
                                                                                    (aset-all! state_9258 5 ex__9190__auto__)
                                                                                    (process-exception state_9258)
                                                                                    :recur)]
                                                          (如果(keyword-identical? ret-value__9188__auto__ :recur))
                                                       (recur state_9258)
                                                      ret-value__9188__auto__)))))
                                                    state__9203__auto__ (f__9202__auto__)
                                                    (aset-all! USER-START-IDX c__9201__auto__)]
            (run-state-machine-wrapped state__9203__auto__))
      c__9201__auto__)




这个问题肯定存在于宏展开中
0票数

评论者:hiredman

看起来问题是,在运行时,let 绑定基本上消失了
因为 ioc 宏将每个表达式绑定到一个名称,所以 let 绑定
在编译时被映射到那些名称。在这个映射中全局
名称实际上映射到自己,因此从全局获取值的 let 绑定
名称消失并成为对全局的引用。

如果您查看 ioc_macros.clj 中 -item-to-ssa:symbol 的情况
,有一个被注释掉的 (add-instruction (->Const x)),如果您取消注释该行并注释掉上面的 fn,我认为您
可以得到期望的行为,但这会在每个全局读取时创建一个局部变量。

您可以根据全局是否声明为动态来选择行为。
,但这还会留下 with-redefs 的问题。在 JVM Clojure 中,无论全局名称是动态的还是静态的,with-redefs 都工作在全局名称上。


如果我们看到全局的 set!,您可以生成某种脏集,并使用该集
合切换行为,但我认为(我不确定)这可能会出现问题,因为
分析只在本地范围内进行。

0票数
_由hiredman发表的评论:

如果按我上面评论中提到的进行更改,清理后的宏展开的相关部分看起来像这样


(let [inst_9257 foo
      inst_9258 foo
      inst_9259 (set! inst_9258 45)
      inst_9260 println
      inst_9261 foo
      inst_9262 (inst_9260 inst_9257 inst_9261)
      inst_9263 foo
      inst_9264 (set! inst_9263 inst_9257)
      state_9266 (aset-all! state_9266 7 inst_9259 8 inst_9262)]
  (return-chan state_9266 inst_9264))



实际上还存在一个bug,因为set! 改变了局部变量的值,而不是全局的 `foo`
0票数

评论者:hiredman

应该检查Clojure ioc宏是否做了同样的事情,因为你可能遇到类似的问题,例如
以下情况:

`
(def ^:dynamic foo 42)

(go (binding [foo 5] (let [x foo] (set! foo 20) (println x))))
`

我期望它输出5,如果存在某种别名错误,可能会输出20

0票数

评论者:hiredman

补丁001造成了从全局初始化的局部变量实际上创建了一个局部变量,并从全局中初始化它,而不是从全局中读取。

0票数

评论者:hiredman

补丁0002是补丁0001,但是使用了在let绑定初始化和循环绑定初始化中使用相同代码路径

0票数

评论者:hiredman

0003为在别名全局变量时预期的局部绑定行为添加了测试

0票数
参考: https://clojure.atlassian.net/browse/ASYNC-165 (由 alex+import 报告)
...