Jon Bristow
Jon Bristow

Reputation: 1725

How do I pass variables as variable names to a function?

I want to be able to do the following pseudocode:

  1. Pass in symbol a.
  2. Pass in symbol b.
  3. Pass in an expression using a and b
  4. As I change the value of a and b, print the output of c at each moment.

Ideally, I would like the signature to look like:

(runner a b (+ a b))

but I'm not sure that I'm approaching this correctly... I've tried changing the function to

(runner 'a 'b (+ 'a 'b))

and this more complicated example:

(runner 'a 'b (+ (* 'a 'b) 'a))

but this does a + on 'a and 'b before stepping into runner.

Here's my first stab at some clojure:

(defn runner [a b c] (
  (for [i (range 10)
        j (range 10)] (println i j (c i j))

What concept of clojure am I missing?

Upvotes: 6

Views: 333

Answers (4)

Brian Carper
Brian Carper

Reputation: 72926

Function arguments are always evaluated before the function is called. If you want to defer evaluation or represent some computation or code as an object, you have a few options:

  1. Use a function (see my code below)
  2. Use a macro and splice some code into some other code that the macro generates
  3. Pass code as a quoted list, and eval it.

Using a function is what you want to do 99% of the time. 1% of the time, you'll want macros. You should never need eval unless you're generating code at runtime or doing very screwy things.

user> (defn runner [f]
        (doseq [a (range 3)
                b (range 3)]
          (println a b (f a b))))
#'user/runner
user> (runner (fn [x y] (+ x y)))
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3
2 0 2
2 1 3
2 2 4

This could also be written as (runner #(+ %1 %2) or even simply (runner +).

There is no need to pass "a" and "b" into the function as arguments. doseq and for introduce their own local, lexically scoped names for things. There's no reason they should use a and b; any name will do. It's the same for fn. I used x and y here because it doesn't matter.

I could've used a and b in the fn body as well, but they would have been a different a and b than the ones the doseq sees. You may want to read up on scope if this doesn't make sense.

Upvotes: 4

Alex Taggart
Alex Taggart

Reputation: 7825

It isn't clear enough to me what you're trying to achieve, but the following is an answer to what I guess is your question:

user=> (declare a b)
#'user/b
user=> (defn runner [] (+ a b))
#'user/runner
user=> (binding [a 1 b 2] (runner))
3
user=> (binding [a 2 b 3] (runner))
5

Note that the above style is likely not what you ought to be doing. Ask a better question and we'll give you better answers.

Upvotes: 0

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91534

I'm not really sure i'm answering the correct question. I'm thinking "if i pass a function a symbol instead of a value how can it use the value that symbol represents? is that close?

(def a 4)
(defn my-inc [x] (+ (eval x) 1))
user> (my-inc 'a)
5

I'm sure there is a more elegant way than using eval.

Upvotes: 0

corsiKa
corsiKa

Reputation: 82559

I would make its signature be something like

(runner alen blen op)

example:

(runner 10 10 +)

Upvotes: 0

Related Questions