store/[org.clojure/clojure "1.8.0"] clj::clojure.core/doseq

Community Documentation

Edit

Arities

[bindings & body] -> nil

Docs

Repeatedly executes the body form(s) (presumably for side-effects) with the bindings and filters. Does not retain the head of the sequence. Returns nil no matter what the result of the body is.

As with clj::clojure.core/for, doseq supports modifiers in the bindings vector. Supported modifiers are:

  • :let [binding-form expr ...] establishes normal non-iterated bindings
  • :while form aborts the entire computation when form is truthy
  • :when form continues at the previous level unless form is truthy

Source

(defmacro doseq
  "Repeatedly executes body (presumably for side-effects) with
  bindings and filtering as provided by \"for\".  Does not retain
  the head of the sequence. Returns nil."
  {:added "1.0"}
  [seq-exprs & body]
  (assert-args
     (vector? seq-exprs) "a vector for its binding"
     (even? (count seq-exprs)) "an even number of forms in binding vector")
  (let [step (fn step [recform exprs]
               (if-not exprs
                 [true `(do ~@body)]
                 (let [k (first exprs)
                       v (second exprs)]
                   (if (keyword? k)
                     (let [steppair (step recform (nnext exprs))
                           needrec (steppair 0)
                           subform (steppair 1)]
                       (cond
                         (= k :let) [needrec `(let ~v ~subform)]
                         (= k :while) [false `(when ~v
                                                ~subform
                                                ~@(when needrec [recform]))]
                         (= k :when) [false `(if ~v
                                               (do
                                                 ~subform
                                                 ~@(when needrec [recform]))
                                               ~recform)]))
                     (let [seq- (gensym "seq_")
                           chunk- (with-meta (gensym "chunk_")
                                             {:tag 'clojure.lang.IChunk})
                           count- (gensym "count_")
                           i- (gensym "i_")
                           recform `(recur (next ~seq-) nil 0 0)
                           steppair (step recform (nnext exprs))
                           needrec (steppair 0)
                           subform (steppair 1)
                           recform-chunk 
                             `(recur ~seq- ~chunk- ~count- (unchecked-inc ~i-))
                           steppair-chunk (step recform-chunk (nnext exprs))
                           subform-chunk (steppair-chunk 1)]
                       [true
                        `(loop [~seq- (seq ~v), ~chunk- nil,
                                ~count- 0, ~i- 0]
                           (if (< ~i- ~count-)
                             (let [~k (.nth ~chunk- ~i-)]
                               ~subform-chunk
                               ~@(when needrec [recform-chunk]))
                             (when-let [~seq- (seq ~seq-)]
                               (if (chunked-seq? ~seq-)
                                 (let [c# (chunk-first ~seq-)]
                                   (recur (chunk-rest ~seq-) c#
                                          (int (count c#)) (int 0)))
                                 (let [~k (first ~seq-)]
                                   ~subform
                                   ~@(when needrec [recform]))))))])))))]
    (nth (step nil (seq seq-exprs)) 1)))

Example 1

Edit
(doseq [x [1 2 3] 
        y [1 2 3]] 
  (prn (* x y)))
;; > 1
;; > 2
;; > 3
;; > 2
;; > 4
;; > 6
;; > 3
;; > 6
;; > 9
;; => nil

Example 2

Edit
;; Keywords :let, :when, and :while are supported, the same as "for"
(doseq [x (range 6)
        :when (odd? x)
        :let [y (* x x)]]
  (println [x y]))
;; > [1 1]
;; > [3 9]
;; > [5 25]
;; => nil

(doseq [x (range 99)
        :let [y (* x x)] 
        :while (< y 30)]
  (println [x y]))
;; > [0 0]
;; > [1 1]
;; > [2 4]
;; > [3 9]
;; > [4 16]
;; > [5 25]
;; => nil

Example 3

Edit
(doseq [[k v] (map identity {:1 1 :2 2 :3 3})] 
  (prn k v))
;; > :1 1
;; > :2 2
;; > :3 3
;; => nil

;; where
(map identity {:1 1 :2 2 :3 3})
;; => ([:1 1] [:2 2] [:3 3])

;; or simply
(doseq [[k v] {:1 1 :2 2 :3 3}]
  (prn k v))
;; > :1 1
;; > :3 3
;; > :2 2
;; => nil

Example 4

Edit
                                        ; Multiple sequences results in a Cartesian cross of their values.
(doseq [a [1 2]
        b [3 4]]
  (println a b))
;; > 1 3
;; > 1 4
;; > 2 3
;; > 2 4
;; => nil

Example 5

Edit
(doseq [[[a b] [c d]] (map list {:1 1 :2 2} {:3 3 :4 4})] 
  (prn (* b d)))
;; > 3
;; > 8
;; => nil

;; where
(map list {:1 1 :2 2} {:3 3 :4 4})
;; => (([:1 1] [:3 3]) ([:2 2] [:4 4]))

Example 6

Edit
(doseq [[x y] (map list [1 2 3] [1 2 3])] 
  (prn (* x y)))
;; > 1
;; > 4
;; > 9
;; => nil

;; where
(map list [1 2 3] [1 2 3])
;; => ((1 1) (2 2) (3 3))

Uses on crossclj