我想通过clojure.core.typed
类型检查传递,但是我遇到了一个我不理解的类型错误。
我的问题是:
这是我的代码(我意识到这是错误的):
(ns clj.util.map
(:require [clojure.core.typed :as t]))
(t/ann map-vals
(All [k v1 v2]
(Fn [ (Fn [(t/Option v1) -> (t/Option v2)])
(t/Option (t/Map k v1)) ->
(t/Option (t/Map k v2)) ])))
(defn map-vals
;; FIXME: Incorrect code
"Apply a function to each of the values in a map, returning the updated map."
[f hm]
(t/doseq> [k :- Any (keys hm)]
(assoc hm k (f (get hm k)))))
以下是lein typed check clj.util.map
的输出:
Initializing core.typed ...
"Elapsed time: 6697.604 msecs"
core.typed initialized.
Start collecting clj.util.map
Finished collecting clj.util.map
Collected 1 namespaces in 6851.111 msecs
Start checking clj.util.map
Checked clj.util.map in 968.041 msecs
Checked 1 namespaces (approx. 21 lines) in 7823.552 msecs
Type Error (clj.util.map:14:23) Polymorphic function clojure.core/keys could not be applied to arguments:
Polymorphic Variables:
k
Domains:
(t/Map k Any)
Arguments:
(t/Option (t/Map k v1))
Ranges:
(t/Seq k) :object {:path [Keys], :id 0}
in: (clojure.core/keys hm)
in: (clojure.core/seq (clojure.core/keys hm))
Type Checker: Found 1 error
Found errors
Subprocess failed
答案 0 :(得分:13)
错误的第一部分告诉您这涉及对clojure.core/keys
的调用。您可以使用(cf keys)
查找类型。
(All [k]
[(Map k Any) -> (Seq k) :object {:id 0 :path [Keys]}])
该错误基本上总结了这种与提供给函数的实际类型并列的多态类型。
Polymorphic Variables
列出All
活页夹中的所有变量及其类型范围。 k
是唯一的变量,它基本上没有边界,因此显示k
。
Domains
按顺序列出所有参数类型(->
左侧)。如果使用Fn
指定了多个arities,则每个参数列表将按顺序显示。
Arguments
显示实际传递给函数的类型。 14:23的代码可能是这个调用(keys hm)
,因此显示第一个参数的类型:(t/Option (t/Map k v1))
Ranges
按顺序列出所有返回类型(->
右侧)。
有时会有Expected
类型,必须与Range
匹配,方式与Arguments
必须与Domain
匹配的方式相同。
我们可以通过将Domains
与Arguments
进行比较来诊断此错误。 Arguments
列表必须位于Domains
的一个列表下,并且会自上而下尝试匹配。如果Domains
没有符合Arguments
,我们会收到类似的错误;通常过于复杂,无法精确确定约束算法失败的位置,因此会向用户提供大量信息。
在这种情况下,我们尝试将参数(t/Option (t/Map k v1))
放在域(t/Map k Any)
下,但失败了。这是因为参数(t/Option (t/Map k v1))
与(U nil (t/Map k v1))
相同,nil
不适合域(t/Map k Any)
。
有几种方法可以解决这个问题。您基本上需要确保keys
未通过nil
。这是一个选项:
(keys (or hm {}))