> Thanks for the response everyone!  I was able to get it working.  If I
> understand what everyone is saying, the following statement is true:
>
> In Clojure, laziness is the rule not the exception.

Rather than that, I'd say that you are thinking about map wrong (hope
that doesn't come across as abrasive).

"Map" in its purest sense says "take a collection of X, apply this
function to each element of it to produce something of type Y and then
give me the resulting collection".  That is, "map" is more geared
towards type "conversion" of the elements in a collection, but it is
only converting the elements in the collection, not the collection
itself.

What you are looking for is something more like reduce.  Reduce (also
known as fold left) consumes a collection and turns it into something
else.  For example, you can implement doseq in terms of reduce as
follows.

(defn permutations
  "creates a sequence of all permutations of multiple sequences"
  [curr-seq & rest-seqs]
  (if (nil? rest-seqs)
    (map #(cons % '()) curr-seq)
    (reduce concat (map (fn [curr-seq-val] (map #(cons curr-seq-val %)
(apply permutations rest-seqs))) curr-seq))))

user=> (permutations '(1 2) '(a b c d))
((1 a) (1 b) (1 c) (1 d) (2 a) (2 b) (2 c) (2 d))
user=> (permutations '(1) '(a b) '(I II III))
((1 a I) (1 a II) (1 a III) (1 b I) (1 b II) (1 b III))

(defmacro mydoseq
  "Uses reduce to implement doseq"
  [forms & body]
  (let [form-pairings (partition 2 forms)
        vars (vec (map #(first %) form-pairings))
        assignments (map #(second %) form-pairings)]
    `(reduce (fn ~'[nothing args] (apply (fn ~vars ~...@body) ~'args))
             nil
             (permutations ~...@assignments))))

user=> (doseq [a '(3 4 5 6)] (println (+ a 2)))
5
6
7
8
nil
user=> (mydoseq [a '(3 4 5 6)] (println (+ a 2)))
5
6
7
8
nil

user=> (doseq [a '(3 4 5) b '(5 4 3)] (println (+ a b)))
8
7
6
9
8
7
10
9
8
nil
user=> (mydoseq [a '(3 4 5) b '(5 4 3)] (println (+ a b)))
8
7
6
9
8
7
10
9
8
nil

user=> (macroexpand '(mydoseq [a '(3 4 5) b '(5 4 3)] (println (+ a b))))
(clojure.core/reduce (clojure.core/fn [nothing args]
(clojure.core/apply (clojure.core/fn [a b] (println (+ a b))) args))
nil (user/permutations (quote (3 4 5)) (quote (5 4 3))))

Which becomes

(reduce
 (fn [nothing args] (apply (fn [a b] (println (+ a b))) args))
 nil
 (permutations '(3 4 5) '(5 4 3))))


Or, you can give a little bit different semantics:

(defn combine
  "combines multiple sequences into a sequence of the collection of
their nth elements"
  [& colls]
  (when (not (some nil? colls))
    (lazy-cons
     (map #(first %) colls)
     (apply combine (map #(rest %) colls)))))

user=> (combine '(1 2) '(a b c d))
((1 a) (2 b))
user=> (combine '(1 2 3 4) '(a b c d))
((1 a) (2 b) (3 c) (4 d))
user=> (combine '(1 2 3 4) '(a b))
((1 a) (2 b))


(defmacro mydoseq2
  "Uses reduce to implement doseq"
  [forms & body]
  (let [form-pairings (partition 2 forms)
        vars (vec (map #(first %) form-pairings))
        assignments (map #(second %) form-pairings)]
    `(reduce (fn ~'[nothing args] (apply (fn ~vars ~...@body) ~'args))
             nil
             (combine ~...@assignments))))


user=> (doseq [a '(3 4 5 6)] (println (+ a 2)))
5
6
7
8
nil
user=> (mydoseq2 [a '(3 4 5 6)] (println (+ a 2)))
5
6
7
8
nil

user=> (doseq [a '(3 4 5 6) b '(6 5 4 3)] (println (+ a b)))
9
8
7
6
10
9
8
7
11
10
9
8
12
11
10
9
nil
user=> (mydoseq2 [a '(3 4 5 6) b '(6 5 4 3)] (println (+ a b)))
9
9
9
9
nil

--~--~---------~--~----~------------~-------~--~----~
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 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to