Thread Macro, Destructuring, and Arity Overloading in Clojure
I've spent much of the last couple weeks working in Clojure and as I've gotten more comfortable with the language I've taken some notes on aspects of the language that were new to me.
-> macro
The arrow, sometimes called the "thread-first" macro because it "threads the expression through the forms", indicates the flow of data from one function to another.
(-> (Math/sqrt 64) int list) ; the result of the first function is the square root of 64, 8 ; that result is passed as an argument to the next function, int ; that result is passed as an argument to the next function, list (list (int (Math/sqrt 64))) ; these are equivalent
To me, this macro can make your code quite a bit more readable because it allows you to process the information from left to right. There's also a function signature convention where the threading macro is used to be more explicit about the purpose of the function.
(defn ->int [s] (Integer/parseInt (str s)))
This function is named ->int because the argument it's passed is converted to an integer (essentially passed in as the first argument to the integer-parsing function).
(defn another-destructuring [attributes] (-> attributes (dissoc :key_1) (dissoc :key_2)))
Again, attributes is passed as an argument to another-destructuring and it becomes the first argument passed to the dissoc function, implying that attributes is a map. The map returned by the dissoc function is then passed as the first argument to the next dissoc function.
(defn double-arrow [sequence] (->> sequence (remove #(= 3 %)) (first)))
The double-arrow threading macro is very similar to the single-arrow except that it passes the argument in as the last argument, rather than the first. In this example, sequence is passed as the last argument to the remove function and the return value of that function is passed as the last argument to the first function.
destructuring
(defn destruct [{:keys [id name]}] (println "id is " id) (println "name is " name)) (destruct {:id 14 :name "Bazooka Joe"}) ; => id is 14 name is Bazooka Joe (let [my-map {:sport "baseball" :animal "giraffe"} {:keys [sport animal] :as binding-entire-expression-to-this} my-map] (println "my map is bound to " binding-entire-expression-to-this) (println "sport is " sport) (println "animal is " animal)) ; => my map is {:sport "baseball" :animal "giraffe"} sport is baseball animal is giraffe
Destructuring is often referred to as a "mini-language" within Clojure. Formally, destructuring is defined as "abstract structural binding", meaning that a data structure, like a map, can be passed as an argument and bound to the respective parts of the expression.
overloading functions
Clojure supports arity overloading in a function.
(defn arity-overloading ([] (arity-overloading {})) ([this-map] (merge {:name "John"} this-map)))
If you invoke the arity-overloading function and do not pass it any arguments, it will call itself and pass itself an empty map and bind it to this-map. If you invoke the function and pass it a map, it will bind that map to this-map.
Some Helpful Stuff
Understanding the Clojure -> macro
Clojure: Functions
Thread Macro From Clojure
Clojure Guide Chapter #8: Arity & Overloading
Stack Overflow: Clojure :: arity-overloaded functions calling each other












