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