我不太了解行为或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)
为什么在这种情况下函数范围没有被评估,如果它确实评估了表达式,下面的例子应该返回相同的类型:
(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}]
但他们会回归不同的类型。
我的直觉是它与常量有关,即当我键入检查包含t / Val的表单时,然后core.typed自动评估它。然而,这并没有解释为什么某些功能不对其进行评估。 2
中的(range 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))
答案 0 :(得分:1)
core.typed
执行完全静态类型检查。
cf
的编译pipleline是read -> analyze -> type check -> eval
。
如果存在静态类型错误,则认为这是致命的。
否则将进行评估。
(cf (/ 1 0))
会抛出运行时错误,因为(/ 1 0)
是一个类型很好的表达式。
原因评估需要与分析Clojure代码的实用性相关 - 如果您分析代码然后不对其进行评估,就会发生奇怪的事情。