Clojure中替代dotimes且返回非nil值的实现方案咨询
dotimes that Returns a Non-Nil Formatted Vector Great question! Since dotimes is built for imperative-style loops focused on side effects (and it always returns nil), we need a functional approach to process your vector and return the formatted collection you want. Here are a few idiomatic Clojure solutions tailored to your needs:
1. The Simplest Approach: map + vec
If you just need to apply a formatting function to every element and collect the results into a vector, map combined with vec is the most straightforward option. map handles iterating over each element and applying your formatter, then vec converts the resulting sequence into a proper vector.
(defn format-collection [format-fn input-vec] (vec (map format-fn input-vec)))
Example Usage:
;; Define your formatting function (defn format-item [x] (str "formatted-" x)) ;; Process the vector (format-collection format-item [1 2 3 4]) ;; Returns: ["formatted-1" "formatted-2" "formatted-3" "formatted-4"]
2. Explicit Accumulation with reduce
If you want to explicitly build the vector step-by-step (similar to how you might use cons in a loop), reduce is perfect. It lets you accumulate results in a vector, using conj to add elements to the end (which is efficient for Clojure vectors):
(defn format-with-reduce [format-fn input-vec] (reduce (fn [accumulator element] (conj accumulator (format-fn element))) [] ; Initial empty vector as accumulator input-vec))
If you specifically want to use cons (which adds elements to the head of a sequence), just add a reverse at the end to get the correct order:
(defn format-with-cons [format-fn input-vec] (reverse (reduce (fn [accumulator element] (cons (format-fn element) accumulator)) [] input-vec)))
3. Loop/Recur for Imperative-Style Control
If you prefer a loop structure that feels more like dotimes (but still returns a non-nil result), use loop + recur. This is Clojure's idiomatic way to write iterative loops without mutable state:
(defn format-with-loop [format-fn input-vec] (loop [remaining-elements input-vec accumulator []] (if (empty? remaining-elements) accumulator ; Return the final vector when done (recur (rest remaining-elements) (conj accumulator (format-fn (first remaining-elements)))))))
Key Notes:
- All these functions return the formatted vector directly (never
nil), which solves your core requirement. - Avoid using
dotimesfor collection transformation tasks in Clojure—it's designed for side effects (like printing, writing to files) rather than building return values. map+vecis the most idiomatic choice for this use case unless you need explicit control over the accumulation process.
内容的提问来源于stack exchange,提问作者Clojurecoder

