On Sep 18, 8:49 pm, Mark McGranaghan <[EMAIL PROTECTED]> wrote:
> Hi all,
>
> I was wondering if there was an idiomatic functional way to accomplish
> the following:
>
> We have some parameters, and we want to build a collection based on
> those parameters.  The collection could have as many as n items, and
> whether and what items get added for each of the n possibilities will
> depend on the parameters.
>
> In Ruby, this might look like:
> def build_coll(a, b)
>   coll = []
>   if a > 2
>     coll << (a * b)
>   end
>   if b > 2
>     coll << (a + b)
>   end
>   if a > b
>     coll << (a - b)
>   end
>   coll
> end
>
> build_coll(3, 1)
>
> I'd like to accomplish this using a purely functional style.  One way
> to do this would be to reduce a collection of test functions with an
> initial empty collection and a reduce function that adds the result of
> the test element if the test passes:
>
> (defn build-coll [a b]
>   (reduce
>     (fn [coll f] (if-let result (f a b) (conj coll result) coll))
>     []
>     [(fn [a b] (if (> a 2) (* a b)))
>      (fn [a b] (if (> b 2) (+ a b)))
>      (fn [a b] (if (> a b) (- a b)))]))
>
> (build-coll 3 1)
>
> Does anyone have any better ideas about how to go about this?
>

For one-off multi-step initialization it's perfectly acceptable to use
let:

(defn build-coll [a b]
  (let [c []
        c (if (> a 2) (conj c (* a b)) c)
        c (if (> b 2) (conj c (+ a b)) c)
        c (if (> a b) (conj c (- a b)) c)]
    c))

Here each c is a new immutable local that hides the previous, but the
effect feels a lot like build-by-assignment.

If this is something you need to do often, a simple macro will remove
any repetition. This macro expands into a let like the one above:

(defmacro conj-cond [coll & test-expr+]
  (let [c (gensym)]
    `(let [~c ~coll
           ~@(mapcat (fn [[test expr]]
                       `(~c (if ~test (conj ~c ~expr) ~c)))
                     (partition 2 test-expr+))]
       ~c)))

Now you could write it like this:

(defn build-coll [a b]
  (conj-cond []
    (> a 2) (* a b)
    (> b 2) (+ a b)
    (> a b) (- a b)))

Rich

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