Search code examples
clojureclojure-java-interop

Clojure: nth not supported on this type: Boolean"


I am trying to implement the dining philosopher example in clojure. For some reasons my program always dies with an exception saying

"java.lang.UnsupportedOperationException: nth not supported on this type: Boolean"

I can't understand this error message since I already tried to get boolean values from a list which worked perfectly with nth

I guess the error happens in the if statement in the function philosopher-thread

Console Prints:

  • 3 is thinking
  • 1 is thinking
  • 4 is thinking
  • 0 is thinking
  • 2 is thinking
  • 0 after sleep
  • 0 after think
  • 0 swap
  • 0 is eating
  • 3 after sleep
  • 3 after think

Code:

(ns dining-philosphers.core
  (:gen-class))

(defn think [n] 
  (println (str n " is thinking"))
  (Thread/sleep (rand 1000))
  (println (str n " after sleep"))
)

(defn eat [n] 
  (println (str n " is eating"))
  (Thread/sleep (rand 1000))
)

(def isEating (atom '(false false false false false)))


(defn philosopher-thread [n] 
  (Thread. #( 
    (while true (do  
      (think n) 
      (println (str n " after think"))
      (if (or  (nth @isEating (mod (- n 1) 5))  (nth @isEating  (mod (+ n 1) 5)))
        (println "is waiting for neighbour")
        (
          do 
          (println (str n " swap"))
          (swap! isEating (fn [l] assoc l n true)) 
          (eat n)
          (swap! isEating (fn [l] assoc l n true))
        )
      )
     )
    ) 
  )

  )
)

(defn -main [& args] 
  (let [threads (map philosopher-thread (range 5))] 
    (doseq [thread threads] (.start thread))
    (doseq [thread threads] (.join thread))))

Solution

  • You're missing some parens here:

    (swap! isEating (fn [l] assoc l n true)) 
    

    should be

    (swap! isEating (fn [l] (assoc l n true))) 
    

    The first will evaluate assoc, l, n and true in order, and return the value of the last expression (true)

    There is still a problem, which is that you can't assoc onto a list. I suggest using a vector instead:

    (def isEating (atom [false false false false false]))