请在 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 (fn (link: n) (+ n 1))) 而不是 (def inc inc),则异常会消失。警告仍然存在。

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定义为不在clojure.core中的用例(如果是这样,为什么?)

(def inc inc)的行为方式的原因是,如果不是绝对必要的,至少在Clojure程序中常见,用于定义递归函数,例如(defn fib (n) (if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2))))),这样在体中都出现的fib可以解析为定义的fib。

0 票数

评论由: alexmiller

将其移至1.7,直到我能更深地查看这个问题。

0 票数

评论者:mikera

Andy - 对于我来说,目前的解决方案是可行的。

我认为这不是一个紧迫的问题,但可能揭示了关于不同时刻命名空间状态的假设的微妙复杂性。也许语义应该是这样的
- def语句本身应该在var被内省之前执行。例如(def inc (inc 5))应该结果是(def inc 6)
- 任何在def语句完成后编译/延迟运行的代码都应该使用新的var(即新的var应由fn、懒序列等引用)

0 票数

评论由: jafingerhut

我不确定在这种情况下您的建议意味着什么

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

第二个inc是在创建新的inc之前还是之后被解释/解析的?因为它是(fn ...),所以它应该是有后行为?除了fn之外,还有什么原因会导致后行为,而不是先行为?

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

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

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

`

我认为当前编译器的行为“在def的身体中,定义的符号始终引用新的变量,而不引用任何早先定义的变量”是相当容易解释的。

0 票数

评论人为:tcrayford

我应该将那个东西中复现的AOT问题作为新问题提交吗?

...