在什么时候评估独特元素的集合。每个人:
(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))
它是编译时和运行时之间的组合吗?
答案 0 :(得分:2)
我想语法#{...}
在读取时间内转换为(hash-set ...)
,并且所有内容都在运行时进行评估,就像任何正常的函数调用一样。在你打电话给foo
的情况下,它首先评估3
,然后评估(+ 1 2)
,然后拨打(foo 3 3)
,然后调用(hash-set 1 2 3 3)
来调用(clojure.lang.PersistentHashSet/create keys)
{1}},将keys
逐个添加到集合中。所以答案是:在运行时删除重复项。
<强>更新强>
正确答案是“两个”。
至于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)
所以:f
编译正常,(f 1 2)
编译正常,执行时抛出异常。
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)
答案 1 :(得分:0)
tl; dr:对于OP代码中的每个案例:编译时间
tl; dr ++:虽然编译时检查哈希集文字(#{...}
)总是,但因为副作用可能会发生,某些情况(并非所有)在运行时另外检查
首先,将op
的名称空间声明添加到OP的代码中,然后将其放入名为op.clj
的文件中
;; op.clj
(ns op)
(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))
其次,将clojure.jar
放入包含文件
第三,将名为compile
#!/bin/bash
java -cp ".:clojure.jar" clojure.main - <<CLJ
(set! *compile-path* ".")
(compile 'op)
CLJ
第四,让compile
可执行并运行它
chmod +x compile
./compile
第五,接收堆栈跟踪
Exception in thread "main" java.lang.IllegalArgumentException: Duplicate key: 3, compiling:(op.clj:3:24)
at clojure.lang.Compiler.compile(Compiler.java:7663)
at clojure.lang.RT.compile(RT.java:408)
at clojure.lang.RT.load(RT.java:453)
at clojure.lang.RT.load(RT.java:421)
at clojure.core$load$fn__7645.invoke(core.clj:6008)
at clojure.core$load.invokeStatic(core.clj:6007)
at clojure.core$load.doInvoke(core.clj:5991)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5812)
at clojure.core$compile$fn__7650.invoke(core.clj:6018)
at clojure.core$compile.invokeStatic(core.clj:6018)
at clojure.core$compile.invoke(core.clj:6010)
at user$eval13.invokeStatic(Unknown Source)
at user$eval13.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:6951)
at clojure.lang.Compiler.load(Compiler.java:7403)
at clojure.lang.Compiler.load(Compiler.java:7350)
at clojure.core$load_reader.invokeStatic(core.clj:4039)
at clojure.main$script_opt.invokeStatic(main.clj:336)
at clojure.main$script_opt.invoke(main.clj:331)
at clojure.main$main.invokeStatic(main.clj:422)
at clojure.main$main.doInvoke(main.clj:385)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: Duplicate key: 3
at clojure.lang.PersistentHashSet.createWithCheck(PersistentHashSet.java:68)
at clojure.lang.LispReader$SetReader.invoke(LispReader.java:1271)
at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:793)
at clojure.lang.LispReader.read(LispReader.java:265)
at clojure.lang.LispReader.readDelimitedList(LispReader.java:1302)
at clojure.lang.LispReader$ListReader.invoke(LispReader.java:1151)
at clojure.lang.LispReader.read(LispReader.java:265)
at clojure.lang.LispReader.read(LispReader.java:198)
at clojure.lang.Compiler.compile(Compiler.java:7561)
... 24 more
第六,回顾第一行(强调我的):线程“main”中的异常java.lang.IllegalArgumentException:重复键:3,编译 :( op.clj:3:24)。
第七,知道发生这种情况在编译时,感到宽慰。
将您的op.clj
文件更改为这样......
;; op.clj
(ns op)
(defn foo
[a b]
#{1, 2, a, b})
(foo 3 (+ 1 2))
尝试再次运行compile
,您将获得另一个堆栈跟踪也从以下开始(强调我的):线程“main”中的异常java.lang.IllegalArgumentException:Duplicate key:3,编译 :( op.clj:3:24)。
再次编译时间!
创建一个名为three
的文件,其中只包含三个数字:
3
将op.clj
修改为如下所示:
;; op.clj
(ns op
(:require [clojure.string :as s]))
(defn foo
[a b]
#{1, 2, a, b})
(foo 3 (-> "three" slurp s/trim Integer/parseInt))
当我试图运行compile
时,我们再次见到我们亲爱的编译时朋友(强调我的):线程“main”中的异常java.lang.IllegalArgumentException:重复键:3 ,编译 :( op.clj:9:5)。
现在修改three
以包含一个
4
运行compile
并注意没有堆栈跟踪!我们杀死了野兽!
现在再次编辑three
返回只包含数字3
3
删除op.clj
所以我们确定只在下一位使用已编译的类文件。
rm op.clj
启动一个repl并需要op
java -cp ".:clojure.jar" clojure.main
Clojure 1.9.0-alpha11
user=> (require 'op)
IllegalArgumentException Duplicate key: 3 clojure.lang.PersistentHashSet.createWithCheck (PersistentHashSet.java:56)
最后! 运行时错误!并且需要花费一些工作才能完成!