jared-nelsen
jared-nelsen

Reputation: 1231

Evaluate Vector of Forms with Parameters

I've been working to figure out a was to evaluate collections of forms with arguments.

An example function:

(defn x
  [a b c]
  (+ a b c))

I would like to evaluate collections of the function x, where only some parameters are defined and others are passed in to end up with a list of the products of the evaluations of the x functions in the collection:

(defn y
  [z]
  (map #(eval %) [(x z 1 1) (x z 2 2) (x z 8 64)]))

The question is: how do I introduce z as a parameter to each of the functions in the collection when I map eval to each? Is this possible?

I am trying to avoid typing them all out because I have many inputs (hundreds) that I want to pass to x where I only have a small set of the second and third parameters (five or so) that I care about.

Is there a better way to accomplish this?

Thanks!

Upvotes: 1

Views: 67

Answers (1)

Taylor Wood
Taylor Wood

Reputation: 16194

First, let's use some more explanatory names, simplify the definition of x, and not use eval:

(defn sum [& xs]
  (apply + xs)) ;; could be inlined instead of a function
(defn sum-with [z]
  (map (partial apply sum)
       [[z 1 1]
        [z 2 2]
        [z 8 64]]))
(sum-with 3)
=> (5 7 75)

But I assume your real world problem is something more complex than summing numbers, so I'll assume your x function is doing something else and requires some positional arguments i.e. the order of arguments matters:

(defn transmogrify [this n1 n2 that]
  (+ n1 n2 (* this that)))
(defn evaluate-sums [a b]
  (map (partial apply transmogrify)
       [[a 1 1 b]
        [a 2 2 b]
        [a 8 64 b]]))
(evaluate-sums 3 9)
=> (29 31 99)

So if I understand correctly, you can accomplish your goal just by applying sequences of arguments to your function. Or to be more explicit with args/not use apply, just use a more specific anonymous function with map:

(defn evaluate-sums [z]
  (map (fn [[this n1 n2 that]]
         (transmogrify this n1 n2 that))
       [[z 1 1 99]
        [z 2 2 360]
        [z 8 64 -1]]))

I am trying to avoid typing them all out because I have many inputs (hundreds) that I want to pass to x where I only have a small set of the second and third parameters (five or so) that I care about.

If your "fixed" arguments are always the same arity, then you can use variadic arity for the rest of the arguments:

(defn sum [a b & cs]
  (apply + a b cs))
(defn evaluate-sums [zs]
  (map (fn [[a b & cs]]
         (apply sum a b cs))
       [[1 1 zs]
        [2 2 zs]
        [8 64 zs]]))

Where zs is a collection/sequence of your extra arguments.

Upvotes: 3

Related Questions