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