It seems that "apply" realizes one more element than is required to a) bind all non-rest arguments and b) determine/validate the arity, in the case that the function has a rest argument.
user=> (defn report-seq [] (iterate (fn [n] (println n) (inc n)) 0)) #'user/report-seq user=> (doall (take 3 (report-seq))) 0 1 (0 1 2) As you can see, this sequence's realization has side effects for all but the first element. Realizing each number after that prints the number that is one lower. user=> (defn test1 [& xs]) #'user/test1 This function has a single rest argument and never uses it. user=> (apply test1 (report-seq)) 0 nil As you can see, apply causes it to call the iterate function once, so it's realizing both the 0 and the 1 at the start of the sequence. In theory it doesn't need to realize any. user=> (defn test2 [x & xs]) #'user/test2 Has a single argument before the rest argument. user=> (apply test2 (report-seq)) 0 1 nil Apply with this one realizes three elements. user=> (defn test3 [x1 x2 & xs]) #'user/test3 user=> (apply test3 (report-seq)) 0 1 2 nil And now four. It seems, in general, to look two elements ahead of where it needs to. Even worse, if given a function without a rest argument and a too-long sequence, it doesn't just halt and generate an arity exception as soon as it discovers 1 more element in the sequence than the maximum arity of the function: user=> (defn test4 [x1 x2]) #'user/test4 user=> (apply test4 (take 10 (report-seq))) 0 1 2 3 4 5 6 7 8 #<CompilerException java.lang.IllegalArgumentException: Wrong number of args (10) passed to: user$eval273$test4 (NO_SOURCE_FILE:0)> It realizes the entire seq! The best case would have been if it had printed user=> (defn test4 [x1 x2]) #'user/test4 user=> (apply test4 (take 10 (report-seq))) 0 1 #<CompilerException java.lang.IllegalArgumentException: Wrong number of args (10) passed to: user$eval273$test4 (NO_SOURCE_FILE:0)> i.e. realized the 0, then the 1 (printing 0), then the 2 (printing 1) as it checked whether there were any more elements in the sequence. Is there a solid reason for this behavior of apply? If you ask me, when the function has rest arguments, it should realize only as much of the sequence as is needed to bind the non-rest arguments and bind the rest argument to (nthrest x the-input-seq), realizing two fewer elements than the current implementation; or if it's desired that the rest argument be bound to nil if that's empty, to (nthnext x the-input-seq), realizing one fewer. And when the function does not, it should *never* realize more than one more than however many elements are in the longest of the function's arglists -- one more in the case that the sequence is longer than the longest arglist, to discover that fact and then throw an exception. Unless, of course, there's a very good reason (efficiency?) for the current behavior (two-element lookahead with rest args, and apparently calling doall or count on the sequence without). -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en