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

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 - 目前对我来说,这个解决方案是可行的。

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

评论者:tcrayford

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

...