Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>EDIT: EVERYTHING I'VE WRITTEN WAS WRONG</strong> </p> <p>When a function with a var-arg is applied to with a seq longer than the number of discrete args, the remainder of the seq is passed as the var-arg (see <a href="http://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RestFn.java#L130" rel="nofollow noreferrer">RestFn.applyTo</a>). </p> <p>To Jürgen: I'm stupid. You're smart. I was wrong. You were right. You're the best. I'm the worst. You're very good-looking. I'm not attractive. </p> <p>The following is a record of my idiocy...</p> <hr/> <p>Responding to Jürgen Hötzel's comment.</p> <p><code>mapcat</code> isn't fully lazy because <code>apply</code> isn't lazy in evaluating the number of args to apply. Further, <code>apply</code> can't be lazy because functions must be invoked with a discrete number of args. Currently if the number of args exceeds 20, the remaining args are dumped into an array, hence non-lazy.</p> <p>So looking at the source for <code>mapcat</code>:</p> <pre> (defn mapcat "Returns the result of applying concat to the result of applying map to f and colls. Thus function f should return a collection." {:added "1.0"} [f & colls] (apply concat (apply map f colls))) </pre> <p>If we expand the evaluation out using the example, the inner <code>apply</code> would evaluate to:</p> <pre> user=> (map seq str-coll) ((\a \b \c \d) (\e \f \g \h) (\j \k \l \m)) </pre> <p>which is fine since the <code>str-coll</code> doesn't get fully realized, but then the outer <code>apply</code> would evaluate to:</p> <pre> user=> (concat '(\a \b \c \d) '(\e \f \g \h) '(\j \k \l \m)) (\a \b \c \d \e \f \g \h \j \k \l \m) </pre> <p>Note that the outer <code>apply</code> applies <em>n</em> arguments to <code>concat</code>, one for each string in the original <code>str-coll</code>. Now, it's true that the result of <code>concat</code> is lazy, and each arg is itself lazy, but you still need realize the full length of <code>str-coll</code> to get those <em>n</em> lazy seqs. If <code>str-coll</code> has 1000 strings, then <code>concat</code> will get 1000 args, and all 1000 strings would need to be read out of the file and into memory before <code>concat</code> could be called.</p> <hr/> <p>For the unbelivers, a demonstration of the seq-realizing behavior of apply:</p> <pre> user=> (defn loud-seq [] (lazy-seq (println "HELLO") (cons 1 (loud-seq)))) #'user/loud-seq user=> (take 3 (loud-seq)) ; displaying the lazy-seq realizes it, thus printing HELLO (HELLO HELLO 1 HELLO 1 1) user=> (do (take 3 (loud-seq)) nil) ; lazy-seq not realized; no printing of HELLO nil user=> (do (apply concat (take 3 (loud-seq))) nil) ; draw your own conclusions HELLO HELLO HELLO nil </pre> <p>And a demonstration that varargs are not lazy:</p> <pre> user=> (defn foo [& more] (type more)) #'user/foo user=> (foo 1 2 3 4) clojure.lang.ArraySeq user=> (apply foo (repeat 4 1)) clojure.lang.Cons </pre> <p>Though as counterpoint, that the following works baffles me:</p> <pre> user=> (take 10 (apply concat (repeat [1 2 3 4]))) (1 2 3 4 1 2 3 4 1 2) </pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload