clojure – 在core.typed中使用conj

core.typed中的以下代码片段

(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)

reduce fn接受Any的ASeq和An​​y类型的另一个参数,并返回一个数字序列.我原以为类型检查器的结果是(t / ASeq t / Num)而不是错误.知道我在这里做错了什么吗?

谢谢.

编辑

谢谢你的回复.我现在能够找出问题所在.目前尚不清楚如何解释core.typed给出的错误信息,但现在它确实有意义.

我现在阅读上面的错误信息如下

Polymorphic Variables:
    a
    c

– >这是reduce函数的变量.你可以用(t / cf reduce)确定它的签名(或类型).它将显示3个arities,但以下消息指定选择了哪个arity以及它为何不匹配.

Domains:
    [a c -> (t/U a (Reduced a))] a (t/Option (Seqable c))

Core.typed也为我们提供了范围.我把它们看成是无法匹配的变量.

Ranges:
    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(减少a))匹配任何a或减少a.我不明白什么减少了一种手段(也许它与传感器有关?),但是t / U只是意味着它可以匹配或者.所以在我们的例子中它只是一个本身.

此示例中缺少的是确保类型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)))

黑客入侵并不令人满意.问题是,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真的是学习如何阅读这些错误信息.但现在似乎不那么难了.感谢您的回答,它帮助我分析了消息并找到了解决方法.

最佳答案 这很可能是因为类型检查引擎无法匹配类型变量a.

看:

域名:[a c – > (t / U a(减少a))] a(t / Option(Seqable c))

参数:[(t / ASeq t / Any)t / Any – > (t / ASeq t / Num)](t / HVec [])(t / ASeq t / AnyInteger)

范围:a

“c”是t / Any,已经完成了.现在为“a”,在左侧 – > “a”是(t / Aseq t / Any),右侧(t / U a(减少a))是(t / ASeq t / Num).它不匹配.我建议将conj-num类型更改为:

[(t / ASeq t / Num)t / Any – > (t / ASeq t / Num)]

点赞