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(与绑定+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 (设置! foo foo)
                                                                                             state_9258 (设置-所有! state_9258 7 inst_9255 8 inst_9254)]
                                                                                              (返回-通道 state_9258 inst_9256)))))]
                                  ((fn state-machine__9187__auto__
                                    ([] (设置-所有! (创建-数组 9) 0 state-machine__9187__auto__ 1 1))
                                    ([state_9258] (let [ret-value__9188__auto__ (try
                                                                                   (循环 []
                                                                                     (let [result__9189__auto__ (switch__9186__auto__ state_9258)]
                                                                                       (如果 (关键字-相同? result__9189__auto__ :recur)
                                                                                        递归)
                                                                                        result__9189__auto__)))
                                                                                    (catch js/Object ex__9190__auto__
                                                                                    (设置-所有! state_9258 5 ex__9190__auto__)
                                                                                    (处理-异常 state_9258)
                                                                                    :recur)
                                                    (if (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中-code>-item-to-ssa的-code>:symbol-code>情况,
下面有一个注释掉的-code>(add-instruction (->Const x)),如果你取消注
释它并注释掉上面的函数,你认为你得到的结果有你所期望的
行为,但代价是每次对全局的读取都创建一个局部变量。

你可以根据全局是否声明为动态来选择某种行为,但是这
还会留下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](https://clojure.atlassian.net/browse/ASYNC-165)(由alex+import报告)
...