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

Community Documentation

Edit

Arities

[bindings body-expr] -> Seq

Docs

For is a macro for concisely expressing list comprehensions. Takes a vector of one or sequence expressions, each of which may be followed by zero or more modifiers, and yields a lazy sequence of evaluations of the body expression. Unlike regular bindings established by clj::clojure.core/let, sequence expressions are bindings understood to be bindings to the elements of a collection. These bindings are iterated in a nested fashion, rightmost fastest, and nested coll-exprs can refer to bindings created in prior binding-forms.

Supported modifiers are:

  • :let [binding-form expr ...] which establishes normal non-iterated bindings
  • :while form which allows for the termination of the sequence when form is truthy
  • :when form which continues unless form is truthy

Notes

For is lazy! This means that you can't really use for to express imperatively performing some operation a bunch of times as one would with an imperative loop. If that's what you're after, clj::clojure.core/doseq is the tool you want.

Source

(defmacro for
  "List comprehension. Takes a vector of one or more
   binding-form/collection-expr pairs, each followed by zero or more
   modifiers, and yields a lazy sequence of evaluations of expr.
   Collections are iterated in a nested fashion, rightmost fastest,
   and nested coll-exprs can refer to bindings created in prior
   binding-forms.  Supported modifiers are: :let [binding-form expr ...],
   :while test, :when test.

  (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))"
  {:added "1.0"}
  [seq-exprs body-expr]
  (assert-args
     (vector? seq-exprs) "a vector for its binding"
     (even? (count seq-exprs)) "an even number of forms in binding vector")
  (let [to-groups (fn [seq-exprs]
                    (reduce1 (fn [groups [k v]]
                              (if (keyword? k)
                                (conj (pop groups) (conj (peek groups) [k v]))
                                (conj groups [k v])))
                            [] (partition 2 seq-exprs)))
        err (fn [& msg] (throw (IllegalArgumentException. ^String (apply str msg))))
        emit-bind (fn emit-bind [[[bind expr & mod-pairs]
                                  & [[_ next-expr] :as next-groups]]]
                    (let [giter (gensym "iter__")
                          gxs (gensym "s__")
                          do-mod (fn do-mod [[[k v :as pair] & etc]]
                                   (cond
                                     (= k :let) `(let ~v ~(do-mod etc))
                                     (= k :while) `(when ~v ~(do-mod etc))
                                     (= k :when) `(if ~v
                                                    ~(do-mod etc)
                                                    (recur (rest ~gxs)))
                                     (keyword? k) (err "Invalid 'for' keyword " k)
                                     next-groups
                                      `(let [iterys# ~(emit-bind next-groups)
                                             fs# (seq (iterys# ~next-expr))]
                                         (if fs#
                                           (concat fs# (~giter (rest ~gxs)))
                                           (recur (rest ~gxs))))
                                     :else `(cons ~body-expr
                                                  (~giter (rest ~gxs)))))]
                      (if next-groups
                        #_"not the inner-most loop"
                        `(fn ~giter [~gxs]
                           (lazy-seq
                             (loop [~gxs ~gxs]
                               (when-first [~bind ~gxs]
                                 ~(do-mod mod-pairs)))))
                        #_"inner-most loop"
                        (let [gi (gensym "i__")
                              gb (gensym "b__")
                              do-cmod (fn do-cmod [[[k v :as pair] & etc]]
                                        (cond
                                          (= k :let) `(let ~v ~(do-cmod etc))
                                          (= k :while) `(when ~v ~(do-cmod etc))
                                          (= k :when) `(if ~v
                                                         ~(do-cmod etc)
                                                         (recur
                                                           (unchecked-inc ~gi)))
                                          (keyword? k)
                                            (err "Invalid 'for' keyword " k)
                                          :else
                                            `(do (chunk-append ~gb ~body-expr)
                                                 (recur (unchecked-inc ~gi)))))]
                          `(fn ~giter [~gxs]
                             (lazy-seq
                               (loop [~gxs ~gxs]
                                 (when-let [~gxs (seq ~gxs)]
                                   (if (chunked-seq? ~gxs)
                                     (let [c# (chunk-first ~gxs)
                                           size# (int (count c#))
                                           ~gb (chunk-buffer size#)]
                                       (if (loop [~gi (int 0)]
                                             (if (< ~gi size#)
                                               (let [~bind (.nth c# ~gi)]
                                                 ~(do-cmod mod-pairs))
                                               true))
                                         (chunk-cons
                                           (chunk ~gb)
                                           (~giter (chunk-rest ~gxs)))
                                         (chunk-cons (chunk ~gb) nil)))
                                     (let [~bind (first ~gxs)]
                                       ~(do-mod mod-pairs)))))))))))]
    `(let [iter# ~(emit-bind (to-groups seq-exprs))]
        (iter# ~(second seq-exprs)))))

Example 1

Edit
(for [x (range 1 6) 
      :let [y (* x x) 
            z (* x x x)]] 
  [x y z])
;; => ([1 1 1] [2 4 8] [3 9 27] [4 16 64] [5 25 125])

Example 2

Edit
(for [[x y] '([:a 1] [:b 2] [:c 0]) :when (= y 0)] x)
;; => (:c)

Example 3

Edit
(defn all-files-present?
  "Takes a list of real file names, and returns a map of files present 1 and not
  present 0."
  [file-seq]
  (for [fnam file-seq
        :let [stat-map {(keyword fnam) (look-for fnam "f")}]]
    stat-map))
;; => #'user/all-files-present?

(into {}
      (all-files-present? '("Makefile" "build.sh" "real-estate.csv")))
;; => {:Makefile 1, :build.sh 1, :real-estate.csv 0}

Example 4

Edit
;; Here are a couple of examples where the only difference is where
;; the :while is placed, but it makes a significant difference in the
;; behavior.

;; When x=2 y=1 is reached, :while (<= x y) evaluates false, so all
;; further items in the y collection are skipped.  When x=3 y=1 is
;; reached, the same thing happens.

(for [x [1 2 3]
      y [1 2 3]
      :while (<= x y)
      z [1 2 3]]
  [x y z])
;; => ([1 1 1] [1 1 2] [1 1 3]
;;     [1 2 1] [1 2 2] [1 2 3]
;;     [1 3 1] [1 3 2] [1 3 3])

;; This is different.  When x=2 y=1 z=1 is reached, :while (<= x y)
;; evaluates false, but since the :while is after the binding for z,
;; all further items in the z collection are skipped.  Then x=2 y=2
;; z=1 is tried, where the while expresssion evaluates true.

(for [x [1 2 3]
      y [1 2 3]
      z [1 2 3]
      :while (<= x y)]
  [x y z])
;; => ([1 1 1] [1 1 2] [1 1 3]
;;     [1 2 1] [1 2 2] [1 2 3]
;;     [1 3 1] [1 3 2] [1 3 3]
;;     [2 2 1] [2 2 2] [2 2 3]
;;     [2 3 1] [2 3 2] [2 3 3]
;;     [3 3 1] [3 3 2] [3 3 3])

Example 5

Edit
(def digits
  (seq [1 2 3]))
;; => #'user/digits

(for [x1 digits x2 digits]
  (* x1 x2))
;; => (1 2 3 2 4 6 3 6 9)

Example 6

Edit
(for [x ['a 'b 'c] 
      y [1 2 3]] 
  [x y])
;; => ([a 1] [a 2] [a 3] [b 1] [b 2] [b 3] [c 1] [c 2] [c 3])

Example 7

Edit
;; Compute the squares over a range using for
;; Equivalent to (map #(* %1 %1) (range 3 7))

(for [x (range 3 7)]
  (* x x))

;; => (9 16 25 36)

Example 8

Edit
;; More examples illustrating the difference between :when and :while

;; Simple but inefficient method of checking whether a number is
;; prime.
(defn prime? [n]
  (not-any? zero? (map #(rem n %) (range 2 n))))
;; => #'user/prime?

(range 3 33 2)
;; => (3 5 7 9 11 13 15 17 19 21 23 25 27 29 31)

;; :when continues through the collection even if some have the
;; condition evaluate to false, like filter
(for [x (range 3 33 2) :when (prime? x)]
  x)
;; => (3 5 7 11 13 17 19 23 29 31)

;; :while stops at the first collection element that evaluates to
;; false, like take-while
(for [x (range 3 33 2) :while (prime? x)]
  x)
;; => (3 5 7)

;; The examples above can easily be rewritten with filter or
;; take-while.  When you have a for with multiple binding forms, so
;; that the iteration occurs in a nested fashion, it becomes possible
;; to write something briefly with 'for' that would be more verbose or
;; unwieldy with nested filter or take-while expressions.

(for [x (range 3 17 2) :when (prime? x)
      y (range 3 17 2) :when (prime? y)]
  [x y])
;; => ([ 3 3] [ 3 5] [ 3 7] [ 3 11] [ 3 13]
;;     [ 5 3] [ 5 5] [ 5 7] [ 5 11] [ 5 13]
;;     [ 7 3] [ 7 5] [ 7 7] [ 7 11] [ 7 13]
;;     [11 3] [11 5] [11 7] [11 11] [11 13]
;;     [13 3] [13 5] [13 7] [13 11] [13 13])

(for [x (range 3 17 2) :while (prime? x)
      y (range 3 17 2) :while (prime? y)]
  [x y])
;; => ([3 3] [3 5] [3 7]
;;     [5 3] [5 5] [5 7]
;;     [7 3] [7 5] [7 7])

;; This example only gives a finite result because of the :while
;; expressions.
(for [x (range) :while (< x 10)
      y (range) :while (<= y x)]
  [x y])

;; => ([0 0]
;;     [1 0] [1 1]
;;     [2 0] [2 1] [2 2]
;;     [3 0] [3 1] [3 2] [3 3]
;;     [4 0] [4 1] [4 2] [4 3] [4 4]
;;     [5 0] [5 1] [5 2] [5 3] [5 4] [5 5]
;;     [6 0] [6 1] [6 2] [6 3] [6 4] [6 5] [6 6]
;;     [7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [7 7]
;;     [8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [8 8]
;;     [9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [9 9])

Example 9

Edit
(for [x [0 1 2 3 4 5]
      :let [y (* x 3)]
      :when (even? y)]
  y)
;; => (0 6 12)

Example 10

Edit
;; Demonstrating difference between :when and :while

(time (dorun (for [x (range 1000) y (range 10000) :when (> x y)] [x y])))
;; > "Elapsed time: 2898.908 msecs"
;; => nil

(time (dorun (for [x (range 1000) y (range 10000) :while (> x y)] [x y])))
;; > "Elapsed time: 293.677 msecs"
;; => nil

Example 11

Edit
;; Demonstrating difference between :when and :while
(for [x (range 3) y (range 3) :when (not= x y)] [x y])
;; => ([0 1] [0 2] [1 0] [1 2] [2 0] [2 1])

(for [x (range 3) y (range 3) :while (not= x y)] [x y])
;; => ([1 0] [2 0] [2 1])

Uses on crossclj