Thanks Rich,

This is exactly the "there must be a simple way to do this that I am
overlooking" answer that I was hoping for.

- Mark

On Fri, Sep 19, 2008 at 8:25 AM, Rich Hickey <[EMAIL PROTECTED]> wrote:
>
>
>
> 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