yazz.com
yazz.com

Reputation: 58826

Clojure: How can I bind a variable?

I have the following defined in clojure:

(def ax '(fn x [] (+ 1 z)))

(let [z 4]
    (str (eval ax))
)

:but instead of returning :

5

: I get :

Unable to resolve symbol: z in this context 

: I have tried changing "let" to "binding" but this still does not work. Does anyone know what is wrong here?

Upvotes: 4

Views: 318

Answers (3)

Iain
Iain

Reputation: 4203

Making the smallest possible changes to your code to get it to work:

(def ^:dynamic z nil)

(def ax '(fn x [] (+ 1 z)))

(binding [z 4]
    (str ((eval ax)))
)

The two changes are defining z as a dynamic var, so that the name resolves, and putting another paren around (eval ax), because ax is returning a function.

A little bit nicer is to change the definition of ax:

(def ^:dynamic z nil)

(def ax '(+ 1 z))

(binding [z 4]
    (str (eval ax))
)

So evaluating ax immediately gets the result you want, rather than returning a function that does it.

Nicer again is to skip the eval:

(def ^:dynamic z nil)

(defn ax [] (+ 1 z))

(binding [z 5]
    (str (ax))
)

But best of all is to not have z floating around as a var, and pass it in to ax as Mimsbrunnr and Joost suggested.

Upvotes: 11

zellio
zellio

Reputation: 32534

Right so I'm not entirely sure what you are trying to do here.

I mean this works, though it's not using eval it's defining x to be the function (fn [ x ] (+ x 1))

> (def x #(+ 1 %))
#'sandbox102711/x
> (x 4)
5

In the end, eval is not something you should be using. As a Lisp Cljoure's support for lambda abstraction and macros ( see the fn definition above ) should remove the need.

Upvotes: 1

Joost Diepenmaat
Joost Diepenmaat

Reputation: 17761

The short answer is don't use eval. You almost never need to, and certainly not here.

For example:

user> (defn ax [z]
         (+ 1 z))
#'user/ax
user> (let [f #(ax 4)]
         (f))
5

Upvotes: 8

Related Questions