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
-~----------~----~----~----~------~----~------~--~---

Reply via email to