liveBook · Manning

Mapcat*

As explained in Clojure: The Essential Reference

mapcat* is a book-specific alternative function that performs mapcat-style transformation while avoiding its initial eager argument evaluation.

mapcat* is a book-specific alternative to mapcat for cases where the usual mapcat expression evaluates its mapped input too eagerly. It retains mapcat-style flattening while delaying concatenation through a lazy step. section 10.4

The implementation follows a small, composable pipeline:

  • Accept a transformation function and zero or more collections. section 10.4
  • Apply map to produce the transformed collections. section 10.4
  • Walk those results lazily, concatenating the first result before recurring on the remainder. section 10.4

Deferring mapped-input evaluation

A regular mapcat expression can print dots while the value is defined: (def a (mapcat range (map #(do (print ".") %) (into () (range 10))))) prints "....". Replacing mapcat with mapcat* uses the lazy step shown in its definition, avoiding that initial eager evaluation. section 10.4

(defn mapcat* [f & colls]
  (letfn [(step [colls]
            (lazy-seq
              (when-first [c colls]
                (concat c (step (rest colls))))))]
    (step (apply map f colls)))) ; #1

(def a (mapcat* range (map #(do (print ".") %) (into () (range 10))))) ; #2

Inspect the complete definition to see how mapcat* combines map, lazy-seq, when-first, and concat. section 10.4

Use mapcat* when preserving mapcat’s transformation-and-concatenation behavior matters, but the first evaluation of mapped arguments should remain deferred. section 10.4

How Clojure: The Essential Reference covers it

How deep it goes
Defines the lazy recursive implementation and contrasts its evaluation timing with mapcat, without developing broader performance behavior.
Examples
Uses a printing map expression to expose mapcat’s eager evaluation and supplies the complete mapcat* definition.
What it assumes
Assumes familiarity with mapcat, map, lazy sequences, and concatenation while leaving the implementation pattern explicit.
What you can do after
Build it from scratch by combining map with lazy-seq, when-first, concat, and recursive traversal.
How it connects
Connects mapcat* to map, concat, lazy sequences, and mapcat’s transformation-and-concatenation behavior.

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.