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

问题在于变量仍然未绑定,并且导致例如以下错误

=> (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

迈克,我认为将你的示例中的(def inc inc)替换为(def inc clojure.core/inc)应该是解决此问题的合理方法,除非你有需要将inc定义为clojure.core之外内容的用例(如果是这样,为什么?)

(def inc inc)之所以这样表现,是因为至少在Clojure程序中,定义递归函数时通常(如果不是绝对必要的话)会使用它,例如(defn fib (link: n) (if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2))))),这样body中fib的出现就解析为所定义的fib。

0 投票

评论者:alexmiller

转向1.7版本,直到我能更深入地研究这个问题。

0 投票

评论者:mikera

艾德尼 - 目前这个方法对我来说是可以的。

我认为这不是一个紧急问题,但它可能暴露了关于不同时间命名空间状态的微妙复杂性。语义可能应该是这样的:
def语句本身应该在var被实习之前执行。例如(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))))

`

我认为当前编译器行为“在一个def体中,定义的符号始终指向新的变量,而不是任何先前的定义的变量”相当直接易懂。

0 投票

评论者:tcrayford

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

...