`reduced?` tests whether its argument is a `clojure.lang.Reduced` marker object. It returns `true` for a wrapped value and `false` for a plain value. The marker signals that a reduction should stop early; testing for it does not itself stop the reduction. section 7.3
Test a wrapped value
(def r (reduced "string")) (reduced? r) ; true (reduced? "string") ; false @r ; "string" The wrapped value supports dereferencing, so `@r` retrieves the string rather than the marker. section 7.3
`reduce` and `reduce-kv` understand the early-stop signal. A custom reduction implementation must check a reducing function's result with `reduced?`, return the unwrapped result when it is reduced, and otherwise continue. Without that check, it may keep processing or pass a marker where an ordinary accumulator is expected. section 7.3 section 11.3.4
(extend-protocol clojure.core.protocols/IKVReduce
java.util.Map
(kv-reduce [m f init]
(let [iter (.. m entrySet iterator)]
(loop [ret init]
(if (.hasNext iter)
(let [^java.util.Map$Entry kv (.next iter)
ret (f ret (.getKey kv) (.getValue kv))]
(if (reduced? ret) ; #1
@ret
(recur ret)))
ret)))))
(reduce-kv
(fn [m k v]
(if (= k :abort)
(reduced m)
(assoc m k v)))
{}
(LinkedHashMap. {:a 1 :abort true :c 3}))
;; {:a 1} ; #2
The Java-map `reduce-kv` extension checks `(reduced? ret)` after each step, returns `@ret` on an early stop, and recurs only for an ordinary accumulator. section 11.3.4
Use `reduced` to create a marker, `reduced?` to recognize one, `ensure-reduced` to avoid wrapping an existing marker again, and `unreduced` to obtain its value when wrapped. section 7.3
