Hi, On Sat, Nov 8, 2008 at 11:20 AM, verec <[EMAIL PROTECTED]> wrote: > > More of an inquiry into the "fp mindset as opposed to the procedural > one" than anything else ... > > If I got this right, there are two forms of iterations: internal and > external. > `map' is an "internal iterator", `doseq' is an "external iterator".
I see where you're going there, but I wouldn't put too fine a point on the distinction between internal and external. Really they're just different syntax for expressing the same thing. The intention behind the "do" forms isn't about "externality" but evaluation strategy. As you know, sequences in Clojure are lazy. The "do" forms force evaluation of a sequence's elements to be done immediately, rather than lazily as needed. A common reason you'd want to do that is because your do-expression has side-effects (I/O) and you want the effects to happen "now" rather than spread out across a set of future time points (or possibly not at all, if the sequence is never evaluated to its end). Ignoring laziness for a moment, all of these iteration constructs can be expressed in terms of loop/recur, since any iteration form can be expressed in terms of recursion. They can also be built up from reduce, which is a form called a "fold" in other functional languages, and is the "internal" equivalent of loop/recur, to borrow your terminology. Using (doall) in conjunction with either of these would let you express the non-lazy "do" forms. The benefit of map, reduce, filter isn't that they are inherently different from loop/recur, but that they concisely express a notion of transforming one sequence into another using a transformation function. If the expression you're trying to build up naturally fits that pattern, then map, reduce, filter are a good fit. (Note, reduce is more general than map/filter, in that it can transform a sequence into something other than another sequence.) Since reduce is the "internal" equivalent to loop/recur, you might consider writing some expressions in both styles until the equivalence makes sense. For example, here are two simple functions described using loop and reduce. (defn add-up [numbers] (loop [nums numbers accumulator 0] (if (nil? nums) accumulator (recur (rest nums) (+ (first nums) accumulator))))) (defn add-up-reducing [numbers] (reduce + 0 numbers)) (defn sum-and-product [numbers] (loop [nums numbers sum 0 product 1] (if (nil? nums) [sum product] (recur (rest nums) (+ (first nums) sum) (* (first nums) product))))) (defn sum-and-product-reducing [numbers] (reduce (fn [[sum prod] frst] [(+ sum frst) (* prod frst)]) [0 1] numbers)) In short, if you can figure out how to write your expression using reduce rather than a loop, it can lead to more compact code. But more complex reduce expressions can be hard to follow, and loop will make for better readability. Hope this helps, Graham --~--~---------~--~----~------------~-------~--~----~ 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 To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---