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

欢迎!请查看 关于 页面以了解如何使用本站更多相关信息。

0
Clojure

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

`
user=> (ns foo)
nil
foo=> (def inc inc)
WARNING: inc already refers to: #'clojure.core/inc in namespace: foo, being replaced by: #'foo/inc

'foo/inc

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

foo=> (ns bar)
nil
bar=> (require ['foo :refer ['inc]])
WARNING: inc already refers to: #'clojure.core/inc in namespace: bar, being replaced by: #'foo/inc
nil
bar=> (inc 8)

IllegalStateException Attempting to call unbound fn: #'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) 在 require foo/inc 时没有错误
c) bar/inc 应当绑定到 foo/inc

22 回答

0

评论由:bronsa

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

0

评论由:mikera

感谢尼古拉指出这一点——我已经编辑了描述。然而错误依旧(只是信息略有不同)

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 already refers to: #'clojure.core/inc in namespace: foo, being replaced by: #'foo/inc

'foo/inc

foo=> (ns bar)
nil
bar=> (require ['foo :refer ['inc]])
WARNING: inc already refers to: #'clojure.core/inc in namespace: bar, being replaced by: #'foo/inc
nil
`

0

评论由:mikera

问题是这个变量仍然是未绑定的,并导致了以下错误

=> (foo/inc 8)
IllegalStateException Attempting to call unbound fn: #'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定义为不在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应通过函数、惰性序列等引用)

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 问题作为一个新问题提交吗?

...