clojure.core.typed/cf in core.typed 什么时候评估和推断类型

when does clojure.core.typed/cf in core.typed evaluate and infer the type

我不太理解行为或 clojure.core.typed/cf 如下所述。

我假设 cf 用于推断表单的类型

(t/cf (+ 1 2)) => Long

现在,这失败了

(t/cf (/ 1 0)) => Error

这向我表明 sexpr 在类型检查之前已经过评估。我曾预计 Long

当我定义自定义函数时:

(t/ann my-fn [t/Any -> t/Num])
(defn my-fn [x]
  (assert (number? x))
  (println "CALLED")
  x)

我可以在同一个表达式中再次使用它,但它失败了,表明确实调用了 fn。

(t/cf (/ 1 (my-fn 0)) => Error, because it evaluates my-fn. no type inference here??

但是,下面的内容对我来说毫无意义。

(t/cf (range)) => (t/ASeq t/AnyInteger)

为什么在这种情况下不计算函数范围,如果它计算了表达式,下面的例子应该return相同的类型:

(t/cf (->> (range 2) vec)) =>  (t/AVec (t/U Short Byte Integer BigInteger Long BigInt))
(t/cf [0 1]) =>  [(t/HVec [(t/Val 0) (t/Val 1)]) {:then tt, :else ff}]

但它们 return 类型不同。

我的直觉是它与 常量 有关,即当我键入检查包含 t/Val 的表单时,然后 core.typed自动评估它。然而,这并不能解释为什么它不对某些功能进行评估。 (range 2) 中的 2 绝对是一个常数,所以为什么会有这种行为差异。

如果在类型检查之前对表单进行评估,那么以下内容应该具有相同的行为

(t/cf (map inc (range 10))))
(t/cf (map #(inc %) (range 10))))

但是 core.typed 确实看到了不同。第二个示例失败,因为匿名 fn 默认接收 t/Any 并且您不能对其调用 inc。所以这意味着 core.typed 必须对表单进行一些分析,并且还要对其进行评估。我承认这有点令人困惑,也许有人可以启发我。

编辑:简短总结

为什么以下关系在某些情况下似乎是正确的,但并非在所有情况下都正确?

(t/cf form) <=> (let [x form] (t/cf x))

core.typed 执行完全静态类型检查。

cf 的编译管道是 read -> analyze -> type check -> eval

如果存在静态类型错误,则视为致命错误。

否则将执行评估。

(cf (/ 1 0)) 抛出运行时错误,因为 (/ 1 0) 是一个类型正确的表达式。

需要原因评估与分析Clojure代码的实用性有关——如果你分析代码而不评估它会发生奇怪的事情。