ehanneken <ehanne...@pobox.com> writes: > I spent a long time debugging some Clojure code yesterday. The > essence of it looked similar to this: > > (defn items [] > (mapcat expensive-function (range 0 4000 100))) > > . . . (take 5 (items)) . . .
I tried to distill the problem down by defining a non-chunking range function (a simple variant), then working outward from there to see what else is evaluating a surprising number of times. ,---- | (defn non-chunked-range | [start end] | (prn (format "In non-chunked-range with %d and %d." start end)) | (lazy-seq | (when-not (= start end) | (cons start (non-chunked-range (inc start) end))))) `---- Note that `mapcat` is defined in terms of `map` and `concat`. First let's confirm that `map` is not eager: ,---- | ;; Draws one, and evaluates lazy sequence function twice: | (take 1 | (map #(list %) | (non-chunked-range 0 10))) `---- Experimenting with the argument to `take` shows that the lazy sequence function is evaluated as expected: a number of times equal to the argument plus one for the terminal case (n + 1). Now add `concat` into the mix to make sure it's not eager: ,---- | ;; Draws two, and evaluates lazy sequence function three times: | (concat (take 2 (non-chunked-range 0 10))) `---- That works as expected. Now add `apply` to `concat` as `mapcat` does to flatten the input lists: ,---- | ;; Draws one, and evaluates lazy sequence five times: | (take 1 | (apply concat | (map #(list %) | (non-chunked-range 0 10)))) `---- Whoah! Where did the extra three evaluations of the lazy sequence function come from? Note that this one calls on the function /five/ times. Here is the mapping of the argument to `take` and the number of times the function is called: take calls ==== ===== 0 5 1 5 2 5 3 5 4 6 5 7 ... n n + 2 I read the source for `concat`, but I don't see what it's doing to force the extra evaluations both below four arguments and the extra one (yielding n + 2) with four or more arguments. What's responsible for this difference in behavior? -- Steven E. Harris -- 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