关于clojure:此类型不支持nth:关键字

nth not supported on this type: Keyword

我是Clojure的新手,作为学习练习,我试图编写一个函数来验证映射中键的存在。

当我尝试运行下面的代码时,出现错误提示

java.lang.UnsupportedOperationException: nth not supported on this type: Keyword

1
2
3
4
5
6
7
8
9
10
(def record {:name"Foobar"})

(def validations [:name (complement nil?)])

(defn validate
  [candidate [key val]]
  (val (get candidate key))

(def actual (every? (partial validate record) validations))
(= true actual)

据我了解,我只是部分地应用了validate函数,并在地图上声明了每个validate函数-但这似乎不起作用-所以我一定会误会某些东西吗?


该错误来自您在validate:[key val]中使用的解构。在幕后,解构使用函数nth,这就是失败的原因。

您的问题是要向every?传递[keyword validation-function]列表。 every?遍历该列表的每个元素,并使用它调用部分应用的validate函数。这意味着您首先使用关键字:name调用validate并引发异常,因为您无法从关键字:name中提取[key val]对,从而导致异常。

要解决此问题,您需要使验证列表像这样列出列表:

1
2
3
4
5
6
7
8
9
10
(def record {:name"Foobar"})
(def validations [[:name (complement nil?)]])

(defn validate
  [candidate [key val]]
  (val (get candidate key)))

(def actual (every? (partial validate record) validations))
(= true actual)
;; => true

这样,every?现在一次遍历每对[keyword validation-function]对,并以此来调用validate。由于这是一对,因此可以将其分解为[key val],一切正常。

众所周知,在新的Clojure版本(1.6及更高版本)中,现在有一个名为some?的功能,该功能等效于(complement nil?)


every?将集合作为第二个参数,您的validate函数也是如此。由于将向量传递给every?,因此将在向量的内容(即:name(complement nil?))上调用validate。您还缺少validate定义中的结束括号。请尝试以下操作:

1
2
3
4
5
6
7
8
9
10
(def record {:name"Foobar"})

(def validations [:name (complement nil?)])

(defn validate
  [candidate [key val]]
  (val (get candidate key)))

(def actual (every? (partial validate record) [validations]))
(= true actual)

顺便说一句,您可以使用some?代替(complement nil?)