Arrow macros are alternatively referred to as threading macros. Threading macros are a group of macros enabling us to pass a value through a sequence of expressions, enhancing code readability and expressiveness.
There are three threading macros in Clojure:
Thread-first macro
Thread-last macro
Thread-as macro
The thread-first macro is represented as ->
in Clojure, and it threads a value through a series of steps, passing the result of each step as the first argument to the next one. This helps create a straightforward and readable chain of transformations on the value.
(-> x & forms)
x
: This is the initial value to be threaded through the forms.
forms
: This is a sequence of forms (expressions) where x
is passed as the first argument to each form.
The following is an example using the thread-first macro ->
:
(def structure {:classes [{:grade :middle-school:students [{:name "Olivia":gender :female:age 8}{:name "Ava":gender :male:age 9}{:name "Emma":gender :female:age 8}{:name "Jack":gender :female:age 9}{:name "Oliver":gender :male:age 8}{:name "James":gender :male:age 9}]}]}); Now, we want to get the first student name of the list of the class using threading(println "First student of the list:"(-> structure:classesfirst:studentsfirst:name))
In the example above, we want to access the first student’s name on the list using the thread-first macro ->
.
Lines 1–19: We specify a list of students with their names
, gender
and age
.
Lines 22-28: We use the thread-first macro ->
to receive the collection as the first argument and return the first student’s name on the list.
The thread-last macro is represented by ->>
in Clojure. It’s like ->
, but it adds the value as the last argument in each step rather than the first. This is handy when using functions that expect the value as the final argument, such as conj
or reduce
.
(->> x & forms)
x
: This is the initial value to be threaded through the forms.
forms
: This is a sequence of forms (expressions) where x
is passed as the last argument to each form.
The following is an example using the thread-last macro ->>
:
(def structure {:students [{:name "Olivia":gender :female:age 8}{:name "Ava":gender :male:age 9}{:name "Emma":gender :female:age 8}{:name "Jack":gender :female:age 9}{:name "Oliver":gender :male:age 8}{:name "James":gender :male:age 9}]})(println "List of male students:"(->> structure:students(filter #(= :male (:gender %)))(map :name)))
In the example above, we want to access the male students and retrieve their names using thread-last macros.
Lines 1–18: We specify a list of students with their names
, gender
and age
.
Lines 21-25: We use the thread-last macro ->>
to receive the collection as the last argument and return a new collection that is the list of male students.
The thread-as macro is represented as as->
in Clojure, and is used when we want to give a specific name to the threaded value within the threading form. It allows us to explicitly name the intermediate result, making our code more readable.
(as-> value name & forms)
value
: This is the value we want to thread through the forms.
name
: This is a symbol to give a name to the threaded value within the scope of the forms.
forms
: This is the forms (expressions) where we can use the named value.
The following is an example using the thread-last macro as->
:
(defn calculate-square [x](as-> x num(* num num)))(println "Square of 5 is:" (calculate-square 5))
In this example,
Line 1: We define a function calculate-square
that takes a number x
.
Line 2: Inside the function, we use the as->
macro to give the name num
to the input x
.
Line 3: Then, we square the number and return the result.
Line 5: When we call (calculate-square 5)
, it calculates the square of 5 and prints the result, which is Square of 5 is: 25
.
Free Resources