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

欢迎!请参阅 关于 页面了解更多关于该功能的信息。

0
Clojure

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

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

'foo/inc

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

foo=> (ns bar)
nil
bar=> (require ['foo :refer ['inc]])
WARNING: inc 已在命名空间 bar 中引用: #'clojure.core/inc,将被替换为: #'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
by

评论者:alexmiller

请看评论...

0
by

评论者:mikera

@Alex 什么评论?注意错误仍然在没有正确语法的情况下发生...

0
by

评论者:mikera

可能过早关闭了

0
by

评论者:alexmiller

我无法在正确的语法下复现

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

'foo/inc

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

0
by

评论者:mikera

问题是变量仍然没有被绑定,导致以下错误,例如

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

我认为这不应该发生 - 或是我在某个地方漏掉了什么?

0
by

评论者:alexmiller

我会看看,但现在还不是时候。 :)

0
by

评论者: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 定义为 clojure.core 之外的东西(如果是这样的话,为什么?)

(def inc inc)像这样工作的原因是,如果不是绝对必要的,至少在Clojure程序中通常用于定义递归函数,例如 (defn fib (link: n) (if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2))))),这样在主体中出现的fib实例就会被解析为已定义的fib。

0

评论者:alexmiller

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

0

评论者:mikera

Andy - 是的,这个替代方案对我来说现在很好。

我认为这不是一个紧急问题,但它可能会揭示关于不同时间点的命名空间状态的假设的微妙复杂性。或许语义应该是这样的
- def 语句本身应在变量被联合之前运行 之前。例如,(def inc (inc 5)) 应该得到 (def inc 6)
- 完成def语句之后编译/延迟执行的任何内容应使用新的变量(即新的变量应由函数、惰性序列等引用)

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 的体内,定义的符号始终指向新的 var,而不是任何较早定义的 vars' 是相当直观的。

0
答:

评论者:tcrayford

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

...