【发布时间】:2015-05-31 20:23:24
【问题描述】:
core.typed中的如下代码sn-p
(defn conj-num [coll x]
(conj coll (byte x)))
(t/cf (t/ann conj-num (t/IFn [(t/ASeq t/Any) t/Any -> (t/ASeq t/Num)])))
(t/cf (reduce conj-num [] (range 10)))
消息失败
Type Error...
Polymorphic function reduce could not be applied to arguments:
Polymorphic Variables: a c
Domains: [a c -> (t/U a (Reduced a))] a (t/Option (Seqable c))
Arguments: [(t/ASeq t/Any) t/Any -> (t/ASeq t/Num)] (t/HVec []) (t/ASeq t/AnyInteger)
Ranges: a
in: (reduce conj-num [] (range 10))
ExceptionInfo Type Checker: Found 1 error clojure.core/ex-info (core.clj:4403)
reducing fn 接受一个ASeq of Any 和另一个Any 类型的参数并返回一个数字序列。我预计类型检查器的结果是 (t/ASeq t/Num) 而不是错误。知道我在这里做错了什么吗?
谢谢。
编辑
感谢您的回复。我现在能够找出问题所在。尚不清楚如何解释core.typed 给出的错误消息,但现在它真的很有意义。
我现在阅读上面的错误信息如下
Polymorphic Variables:
a
c
-> 这是reduce 函数的变量。您可以使用(t/cf reduce) 确定它的签名(或类型)。它将显示 3 个 arity,但以下消息指定选择了哪个 arity 以及它不匹配的原因。
Domains:
[a c -> (t/U a (Reduced a))] a (t/Option (Seqable c))
Core.typed 也给了我们范围。我把它们读作无法匹配的变量。
Ranges:
a
所以我们必须关注a。 Core.typed 似乎对 b 很满意。
以下消息是关于被匹配的实际类型(我们的参数类型与reduce fn 定义的类型匹配)。
Arguments:
[(t/HVec [t/Num]) t/Any -> (t/HVec [t/Num])] (t/HVec []) (t/ASeq t/Num)
我们手动匹配
[(t/HVec [t/Num ]) t/Any -> (t/HVec [t/Num])] (t/HVec []) (t/ASeq t/Num)
-------------- ----- ---------------- -------- ------------
a b (t/U a (Reduced a) a (t/Option ...)
以下内容现在很明显
-
a必须是(t/HVec [t/Num])类型,因为第一次出现并且(t/HVec [])因为a第二次出现。由于不能同时使用它们,因此 core.typed 正确失败。 -
(t/U a (Reduced a))类型匹配任何a或简化的a。我不明白Reduced a是什么意思(也许它与传感器有关?),但t/U只是意味着它可以匹配或匹配。所以在我们的例子中,它只是a本身。
这个例子中缺少的是确保类型 a 必须在两边都匹配,例如:
;; a is still a vector
(def a [])
;; we give the type (t/HVec [t/Num]) to a. This makes it *more* compatible with our conj-num fn.
(t/cf (t/ann a (t/HVec [t/Num])))
;; core.typed is happy now ;)
(t/cf (reduce conj-num a (range 10)))
破解a 并不令人满意。问题是 conj-num 没有以有用的方式定义。它非常僵硬。它基本上不允许累加器只是一个向量。这是最终类型:
(t/cf (t/ann conj-num
(t/IFn [(t/U (t/HVec [])
(t/HVec [t/Num])) t/Num -> (t/HVec [t/Num])])))
;; great. we can now use [] as input.
(t/cf (reduce conj-num [] (range 10)))
此签名现在有效,因为第一个参数 a 现在可以是空向量 (t/HVec []) 或 nums 向量 (t/HVec [t/Num]) 这正是 conj-num 返回的内容。所以现在一切都好。看来学习core.typed 真的是学习如何阅读这些错误信息。但现在似乎不那么难了。感谢您的回答,它帮助我分析了消息并找到了解决方法。
【问题讨论】:
-
[(t/U (t/HVec []) (t/HVec [t/Num])) t/Num -> (t/HVec [t/Num])] t/HVec []) 是不必要的。 (t/HVec [t/Num]) 类型检查 [] (空 vec)。
标签: clojure clojure-core.typed