【问题标题】:usage of conj in core.typed在 core.typed 中使用 conj
【发布时间】: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

所以我们必须关注aCore.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


【解决方案1】:

这很可能是因为类型检查引擎无法匹配类型变量a。

看:

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

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

范围:一个

"c" 是 t/Any,这样就完成了。现在对于“a”,->“a”的左侧是 (t/Aseq t/Any),右侧 (t/U a (Reduced a)) 是 (t/ASeq t/Num)。它不匹配。我建议将 conj-num 类型更改为:

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

【讨论】:

  • 感谢您的解释。它帮助我找到了解决方案。查看我的编辑。
【解决方案2】:

你的命令的顺序意味着你的函数conj-num没有被检查。

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

(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的定义与注解不对应,应该抛出类型错误。

【讨论】:

  • 是的,我正在 repl atm 中测试 core.typed。你对注释问题是正确的。我只是不清楚。我认为它会自动为我解决问题。我了解到您的注释必须非常精确,否则您会遇到麻烦。但这似乎没有我最初预期的那么难。感谢这个漂亮的 clojure 库。
  • 我不确定我是否正确读取了 core.typed 的错误消息。我对我的问题进行了编辑并描述了我如何解释它。你能告诉我我的解释是正确的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多