在什么时候评估集合的唯一元素。对于每个:
(def set1 #{1, 2, 3, 3})
(def set2 #{1, 2, 3, (+ 1 2)})
(defn foo
[a b]
#{1, 2, a, b})
(foo 3 (+ 1 2))
它是编译时和运行时的组合还是其他什么?
最佳答案
我猜语法 #{...}
在读取时会转换为 (hash-set ...)
,并且所有内容都会被评估在运行时,就像任何正常的函数调用一样。在您的情况下,当您调用 foo
时,它首先评估 3
,然后评估 (+ 1 2)
,然后调用 (foo 3 3)
,它又调用 (hash-set 1 2 3 3)
导致调用 (clojure.lang.PersistentHashSet/create keys)
,这增加了key
来一一设置。所以答案是:重复项在运行时被消除。
更新
正确答案是“两者”。
对于 op 的示例,它显然是在运行时执行的,这在 repl 中很容易看出:
user> (defn f [a b]
(println "f" a b)
#{1 2 a b})
#'user/f
user> (f 1 2)
f 1 2
IllegalArgumentException Duplicate key: 1 clojure.lang.PersistentHashSet.createWithCheck (PersistentHashSet.java:56)
so: f
编译正常,(f 1 2)
编译正常,执行时抛出异常。
正如 @Hoagy Carmichael 的回答中提到的,将相同的内容放入文件并使用 clojure 编译会引发错误,但这并不是因为编译器检查重复项,而是由于内部编译器在运行顶级表单后的行为汇编。所以这不是真正的编译时错误,而是运行时错误。而且,由于这是内部行为,我想没有人保证将来会是这样。
另一方面,当我粗略地简化了读者的行为时,我错了:它确实检查了传递给 #{} 表单的所有表单的“字面”唯一性。所有这些函数定义都无法编译:
user> (defn f1 [a b]
#{1 1 a})
IllegalArgumentException Duplicate key: 1
user> (defn f1 [a b]
#{1 a a})
IllegalArgumentException Duplicate key: a
user> (defn f1 [a b]
#{1 (inc a) (inc a)})
IllegalArgumentException Duplicate key: (inc a)
user> (defn f1 [a b]
#{1 @a @a}) ;; notice that at run-time `@a` could easily produce different vals. But the reader sees equal forms.
IllegalArgumentException Duplicate key: (clojure.core/deref a)
user> (defn f1 [a b]
#{1 (+ a b) (+ a b)})
IllegalArgumentException Duplicate key: (+ a b)
关于clojure - 何时评估集合的唯一元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39191323/