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

欢迎!请参阅关于页面以了解更多关于如何使用本站的信息。

0
Clojure

以下代码失败(在1.6和最新的1.7-alpha4版中都如此)

`
user=> (ns foo)
nil
foo=> (def inc inc)
WARNING: inc已经引用: #'clojure.core/inc 在命名空间: foo, 正被替换为: #'foo/inc

'foo/inc

;; 注意此刻inc未绑定,这会导致以下异常
foo=> inc

foo=> (ns bar)
nil
bar=> (require ['foo :refer ['inc]])
WARNING: inc已经引用: #'clojure.core/inc 在命名空间: bar, 正被替换为: #'foo/inc
nil
bar=> (inc 8)

IllegalStateException 尝试调用未绑定函数: #'foo/inc clojure.lang.Var$Unbound.throwArity (Var.java:43)
`

进一步调查显示foo/inc未绑定

foo/inc
=> #

进一步调查还显示,将(def inc inc)替换为几乎任何其他内容,例如(def inc dec),(def inc clojure.core/inc)或(def inc (fn (link: n) (+ n 1))),都不会引发异常(但警告仍存在)。

我原本期望
a) foo/inc应该被绑定,并具有与clojure.core/inc相同的值
b) 使用foo/inc时无错误
c) bar/inc应绑定到foo/inc

22 个答案

0

评论者:bronsa

第二个错误本应可预期,正确的语法应为(require (link: 'foo :refer ['inc])) (注意inc前面的引号)

0

评论者:mikera

感谢Nicola的纠正 - 我已编辑了描述。但是错误信息略有不同,仍然存在相同的错误。

0

评论者:alexmiller

查看评论...

0

评论者:mikera

@Alex 什么评论?注意,即使使用了正确的语法,错误仍然会发生....

0

评论者:mikera

似乎关闭得太早了

0

评论者:alexmiller

我用正确的语法无法重现

`
Clojure 1.7.0-master-SNAPSHOT
user=> (ns foo)
nil
foo=> (def inc inc)
WARNING: inc已经引用: #'clojure.core/inc 在命名空间: foo, 正被替换为: #'foo/inc

'foo/inc

foo=> (ns bar)
nil
bar=> (require ['foo :refer ['inc]])
WARNING: inc已经引用: #'clojure.core/inc 在命名空间: bar, 正被替换为: #'foo/inc
nil
`

0

评论者:mikera

问题在于 var 仍然未绑定,并导致以下错误

=> (foo/inc 8)
IllegalStateException 尝试调用未绑定函数: #'foo/inc clojure.lang.Var$Unbound.throwArity (Var.java:43)

我认为这不应该发生 - 或者我缺少什么吗?

0

评论者:alexmiller

啊,我会看看。但现在还不会。 :)

0

评论者:jafingerhut

更新了描述并添加了一些更多细节。如果在例如 (def inc inc) 处改为 (def inc (fn (link: n) (+ n 1))),异常就会消失。但警告仍然存在。

0

评论者:tcrayford

不确定这是否是同一问题(我认为可能是?),但我通过使用AOT编译重现了完全相同的错误信息

在以下git仓库中重现:https://github.com/yeller/compiler_update_not_referenced_bug

克隆它,运行lein do clean, uberjar, test,这个错误信息会对我每次都出现

0

评论者:jafingerhut

Mike,我认为将你的示例中的(def inc inc)替换为(def inc clojure.core/inc)可以被认为是针对此问题的合理解决方案,除非你有某些用例需要将 inc def到不在 clojure.core 中的某个东西(如果是这样,为什么?)

(def inc inc)表现出这种行为的原因是,如果不是绝对必要的,至少在Clojure程序中被广泛用于定义递归函数,例如(defn fib (n)(if (≤ n 1)1 (+ (fib (dec n)) (fib (- n 2))))),以便解析函数体中fib的出现。

0

评论者:alexmiller

转到1.7版本,直到我能更深入地查看这个问题。

0

评论者:mikera

Andy - 目前对于这个解决方案来说很合适。

我认为这不是一个紧急的问题,但它可能暴露了有关不同时间命名空间状态的假设的微妙复杂性。或许语义应该是这样的
- def语句自身应该在var被intern之前执行。例如,(def inc (inc 5))应该导致(def inc 6)
- 在def语句完成后运行的任何编译/延迟执行的代码都应该使用新的var(即,新var应该由函数、延迟序列等引用)

0

评论者:jafingerhut

我不确定你的建议在这种情况下是什么意思

(def inc (fn [x] (inc x)))

第二次增量是在创建新的增量之前还是之后进行解释/解决?因为它是(fn ...),所以应该是之后的行为?除了fn之外,还有哪些事情会导致之后的行为,而不是之前的行为?

更有趣的是(不是在说人们经常这样写代码,但编译器今天可以处理它)

`
(def inc (if (> (inc y) 5)

       (fn [x] (inc x))
       (fn [x] (dec x))))

`

我认为当前编译器行为“在定义体中,定义的符号始终指向新变量,而不是任何先前的定义变量”是相当简单的解释。

0

评论者:tcrayford

我应该将事情中重现的AOT问题作为一个新问题提交吗?

...