关于clojure:core.typed中conj的用法

usage of conj in core.typed

core.typed

中的以下代码段

1
2
3
4
5
6
(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)))

失败,显示消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)

化简fn接受一个ASeq of Any和另一个类型为Any的参数,并返回一个数字序列。我期望类型检查器的结果是(t/ASeq t/Num)而不是错误。知道我在这里做错了吗?

谢谢。

编辑

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

我现在如下读取错误消息

1
2
3
Polymorphic Variables:
    a
    c

->这是reduce函数的变量。您可以使用(t/cf reduce)确定其签名(或类型)。它会向您显示3种arities,但是以下消息指定了选择了哪种arity以及为什么不匹配。

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

core.typed也为我们提供了范围。我将它们视为无法匹配的变量。

1
2
Ranges:
    a

所以我们必须专注于acore.typed似乎对b感到高兴。

以下消息是关于匹配的实际类型的(我们的参数的类型与reduce fn定义的类型匹配)。

1
2
Arguments:
    [(t/HVec [t/Num]) t/Any -> (t/HVec [t/Num])] (t/HVec []) (t/ASeq t/Num)

我们手工匹配

1
2
3
[(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 [])也必须是(t/HVec []),因为第二次出现a。由于不能同时使用两者,因此core.typed正确会失败。
  • 类型(t/U a (Reduced a))匹配任何a或简化的a。我不明白Reduced a的含义(也许与传感器有关?),但是t/U只是意味着它可以匹配或匹配。因此,在我们的情况下,它只是a本身。

此示例中缺少的是确保类型a必须在两侧都匹配,例如:

1
2
3
4
5
6
7
8
9
;; 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只是没有以有用的方式定义。它非常僵化。它基本上不允许累加器只是一个向量。这是最终的类型:

1
2
3
4
5
6
(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确实是关于学习如何阅读这些错误消息。但是现在看来不那么困难了。感谢您的回答,它帮助我分析了消息并找到了解决方法。


命令的顺序意味着未检查功能conj-num

我建议改为在文件中检查。

1
2
3
4
5
6
7
8
(ns typed.test
  (:require [clojure.core.typed :as t]))

(t/ann conj-num (t/IFn [(t/ASeq t/Any) t/Any -> (t/ASeq t/Num)]))
(defn conj-num [coll x]
  (conj coll (byte x)))

(reduce conj-num [] (range 10))

conj-num的定义与注释不对应,因此应引发类型错误。


这很可能是因为类型检查引擎无法匹配类型变量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(Reduced a))是(t / ASeq t /数字)。不匹配。我建议将conj-num类型更改为:

[(t / ASeq t / Num)t /任意->(t / ASeq t / Num)]