Reputation: 81
I'm new to Clojure and as a learning exercise I'm trying to write a function that validates the present of keys in a map.
when I try to run the code below I get an error saying
java.lang.UnsupportedOperationException: nth not supported on this type: Keyword
(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)
As I understand I'm partial applying the validate function and asserting every validations function on the map - but it doesn't seem to work - so I must be misunderstanding something?
Upvotes: 0
Views: 2513
Reputation: 219
every?
takes a collection as the second argument, and so does your validate
function. Since you're passing a vector to every?
, validate
is being called on the contents of the vector (that is, :name
and (complement nil?)
). You're also missing a closing paren in the definition of validate
. Try the following:
(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)
BTW, you could use some?
instead of (complement nil?)
Upvotes: 1
Reputation: 4816
The error is coming from the destructuring that you are using in validate: [key val]
. Under the hood, destructuring uses the function nth
, and that's what's failing.
Your issue is that you are passing to every?
a list of [keyword validation-function]
. And every?
is iterating over each element of that list and calling the partially applied validate function with it. That means that your validate is called first with the keyword :name
and that throws an exception, because you can not extract a [key val]
pair out of the keyword :name
, causing the exception.
To fix it, you need to make your validations list a list of lists as so:
(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
That way, every?
is now iterating over each pair of [keyword validation-function]
, one at a time, and calling validate with that. Since this is a pair, it can be destructured into a [key val]
and everything works.
And just so you know, in newer Clojure versions (1.6 and above), there is now a function called some?
which is equivalent to (complement nil?)
.
Upvotes: 1