Experiencing beauty of thread macro in Clojure

While studying the Union-Find algorithm during the Algorithms, Part I course at coursera.org, I developed some functions to help me understand the topic in practice.

Here’s a list of 10 consecutive numbers and the union function with its application.

(def ids (range 10))

(defn union [ids p q]
  (let [pid (nth ids p)
        qid (nth ids q)
        pid->qid (fn [id] (if (= id pid) qid id))]
    (map pid->qid ids)))

;; execute union three times
(union (union (union ids 2 6) 3 8) 6 3)

Think how the above three-union form would change with four or more unions. I’m pretty sure you’ve noticed the pattern – the innermost form (union ids 2 6) is executed before its result is passed to another down and so on. It repeatedly calls union with a list as the first input parameter (or the second element of the “union” list). When I saw the threading pattern, the thread macro -> sprung to my mind. With it applied the calls are so much clearer. Have a look.

(-> ids
    (union 2 6)
    (union 3 8)
    (union 6 3)
    (union 8 5)
    (union 9 8)
    (union 7 4))

The -> macro just “threads” (or weaves?) the ids list through union calls.

When I learnt the thread -> macro I was looking for use cases where it’d shine. It did in some samples, but it was just today when I experienced its beauty in a real-life example and realized its potential. I’m so glad I learnt it before and knew about it so I could apply it now!

p.s I still wonder if there’s a more idiomatic way to write the pid->qid function in union. Anybody?

Be Sociable, Share!
This entry was posted in Languages.

4 Responses to Experiencing beauty of thread macro in Clojure

  1. Jacek,

    For pid->qid I would probably prefer using “case”:
    pid->qid (fn [id] (case id pid qid id))]

    And for your sequence of unions, isn’t it a case for folding(reducing)?
    (reduce #(union %1 (first %2) (second %2)) ids ‘((2 6)(3 8)…))

    Warning: not tested!

    • case is awesome! I like it and will use thoroughly from now on.

      As to reduce, I’d prefer -> in my version which reads nicer. It was very thought-provoking to see your proposal as it’s very clever. Thanks!

  2. Abraham says:

    I like this very nice..how about using names such as nodes / node instead of p , q , id …

    • Well, I could’ve named it differently, but since I’ve just begun my journey into algorithms I meant to be as close to the imperative one as possible, and hence the variable names. I should be more careful in the upcoming exercises.

Leave a Reply

%d bloggers like this: