liveBook · Manning

Threading macro

As explained in Clojure: The Essential Reference

A thread-first macro rewrites a sequence of calls by inserting the threaded value as the first argument of each call.

A threading macro makes a processing pipeline read in the order its steps run. The thread-first macro `->` starts with an expression and inserts its value as the first argument of each following form. This is useful when nested calls would otherwise make a sequence of transformations read from the inside out. section 2.3.1

Reading a thread-first pipeline

`(-> {:a 2} :a inc)` returns `3`. The keyword step receives the map, producing `2`; `inc` receives that result. Macroexpansion shows the equivalent nested call: `(inc (:a {:a 2}))`. section 2.3.1

The placement rule determines when `->` fits:

  • Supply an initial expression; further forms are optional. A bare callable such as `inc` is treated as a call form, and each step receives the preceding result in first-argument position. Calling `->` without an initial expression raises an `ArityException`. section 2.3.1
  • Use `->>` when the value belongs at the end of each form. If its position changes between steps, `as->` provides a named placeholder that can be placed where needed. section 2.3.5
  • Threading rewrites forms; it does not turn every form into a function value. For example, `(-> 1 (fn [x] (inc x)))` expands with `1` inserted into the `fn` form and fails. section 2.3.1
(defn prepare [req] ; #1
  (-> req
      (assoc :url (str (:host req) (:path req))
             :coord [(Double/valueOf (:x req)) (Double/valueOf (:y req))])
      (dissoc :x-forward-to :x :y)
      (update :trace conj :prepared)))

Follow a request map through `assoc`, `dissoc`, and `update`: each operation receives the map returned by the preceding step, making the preparation order visible. section 2.3.1

How Clojure: The Essential Reference covers it

How deep it goes
Works through argument insertion and macroexpansion, then states the input contract and illustrates a failing form.
Examples
Uses keyword lookup followed by increment and a request-map pipeline that adds, removes, and updates fields.
What it assumes
Assumes basic Clojure expressions and function calls while explaining the threading rewrite step by step.
What you can do after
Apply it via Clojure’s `->` macro to rewrite suitable nested transformations as first-argument pipelines.
How it connects
Contrasts thread-first `->` with thread-last `->>` and placeholder-based `as->`, alongside function composition and macroexpansion.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.