One of the early mental hurdles that must be cleared when learning Clojure is the application of threading macros.
The difficult thing about the thread-first and thread-last macros is that you have to mentally fill in the results being 'threaded' through the forms. Here's an interesting example from the thread-last docs:
;; An example of using the "thread-last" macro to get ;; the sum of the first 10 even squares. (->> (range) (map #(* % %)) (filter even?) (take 10) (reduce +))
The difficult thing for the beginner is to imagine the result of each form being 'threaded':
(->> (range) (map #(* % %) <result-of-range>) (filter even? <result-of-map>) (take 10 <result-of-filter>) (reduce + <result-of-take>))
If you simplify
<result-of-*> (above) to something like
$ you get this:
(->> (range) (map #(* % %) $) (filter even? $) (take 10 $) (reduce + $))
...which is remarkably similar to the exact mechanics of
(as-> (range) $ (map #(* % %) $) (filter even? $) (take 10 $) (reduce + $))
Here's an example of how I used
as-> to prepare some hand-crafted html for a test assertion against the output from hiccup:
(let [tags (my-function-to-generate-tags) lines ["<html> " " <head> " " </head> " " <body> " " <h1> " " Welcome! " " </h1> " " <form action='/other/page' method='POST'> " " <label for='foo'>Enter Foo:</label> " " <input id='foo' name='foo' type='number' value='3' /> " " <input type='submit' value='Foo' /> " " </form> " " </body> " "</html> "]] (should= [:html ...] tags) (as-> lines $ (map string/trim $) (apply str $) (string/replace $ "'" "\"") (should= $ (hiccup/html tags))))
as-> macro is much more flexible than
->> and allows for easier visualization of what the macro is doing for you. Let's use it instead to introduce the concept of threading macros!
But wait, there's more! Head over to part 2.