我在我的项目中实施core.typed注释。以下代码工作正常:
(require ['clojure.core.typed :as 't])
(t/ann foo [String String -> String])
(defn foo [x y]
(str x y))
(t/ann works [String String -> String])
(defn works [x y]
(t/let [z :- (t/Vec String), (shuffle [x y])
a :- String, (nth z 0)
b :- String, (nth z 1)]
(foo a b)))
如果我稍微改变了函数定义,我会遇到几个不同的错误:
(t/ann fails-1 [String String -> String])
(defn fails-1 [x y]
(t/let [z :- (t/Vec String), (shuffle [x y])
; Fails because (t/Vec String) is not included
; in the domain of first or second
a :- String, (first z)
b :- String, (second z)]
(foo a b)))
(t/ann fails-2 [String String -> String])
(defn fails-2 [x y]
(t/let [[a b] :- (t/Vec String), (shuffle [x y])]
; Fails because a and b are of type (t/U nil String)
(foo a b)))
从类型的角度来看,我原本预计这三个例子或多或少是等价的。具体来说,我假设:
(t/Vec String)
将位于nth
和first
(shuffle [x y])
和nil
类型为x
y
的范围不包括String
这是core.typed的限制,还是我有一个根本的误解?
答案 0 :(得分:1)
现在要理解的主要内容是nth
,以及具体如何使用nth
进行解析。
(∀ [x y]
(λ [(∪ (∩ Sequential (Seqable x)) (Indexed x)) AnyInteger → x]
[(∪ nil (∩ Sequential (Seqable x)) (Indexed x)) AnyInteger y → (∪ x y)]
[(∪ nil (∩ Sequential (Seqable x)) (Indexed x)) AnyInteger → (∪ nil x)]))
如果没有默认值nth
,如果在其边界之外传递集合和索引,则会抛出异常。键入的Clojure不会尝试阻止此异常。
(t/cf (t/fn [a :- (t/ASeq t/Int)] :- t/Int (nth a 0)))
;=> [(t/IFn [(t/ASeq t/Int) -> (t/U Integer Long BigInt BigInteger Short Byte)]) {:then tt, :else ff}]
使用默认值时,默认值始终是结果类型的一部分。
(t/cf (t/fn [a :- (t/ASeq t/Int)] :- (t/U nil t/Int) (nth a 0 nil)))
=> [(t/IFn [(t/ASeq t/Int) -> (t/U nil Integer Long BigInt BigInteger Short Byte)]) {:then tt, :else ff}]
向量解构扩展为nth
,默认值为nil。
另请注意,shuffle的返回类型没有长度信息。有时,异构数据结构的解构比同类数据结构更准确。