Search code examples
clojure

nth not supported on this type: Keyword


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?


Solution

  • 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?).