Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic let in Clojure?

I have the following happening in the REPL:

mathematics.core> (let [zebra 1] (resolve 'zebra))
nil
mathematics.core> (def zebra 1)
#'mathematics.core/zebra
mathematics.core> (let [zebra 2] (when (resolve 'zebra) (eval 'zebra))) 
1

Basically, I would like to dynamically bind values to variables using something like a let form, and have functions inside that form be able to access the value the variable is bound to.

mathematics.core> (def ^:dynamic zebra 1)
#'mathematics.core/zebra   
mathematics.core> (binding [zebra 2] (when (resolve 'zebra) (eval 'zebra))) 
2

binding seems to do the trick I want, but AFAIK it requires a variable to be defined with the :dynamic metadata first. I want to be able to use variables that have never been defined before on the fly, and have expressions in the form be able to access that variable as if it were actually defined.

To illustrate, I want something like this:

mathematics.core> (let-dynamic [undefined-variable 1]
                    (when (resolve 'undefined-variable) (eval 'unresolved-variable)))
1

Is there an easy way to do this? Or a way to accomplish this using macros?

like image 827
wrongusername Avatar asked Jan 17 '23 17:01

wrongusername


1 Answers

This isn't going to work particularly well. If the symbol isn't defined, then the Clojure compiler can't compile any code that uses it. You might be able to get some kind of hack working with macros that call def lazily when needed, but it would be some pretty nasty code.....

I would suggest just using binding, and define your vars in advance. You should be able to write your code in the way that this works.

I think it's a bad idea to define variables "on the fly". I don't think you should ever really need this - if you are using the variable in the code, surely it is easy enough just to do a (def ^:dynamic ...) beforehand for each variable that you use?

like image 178
mikera Avatar answered Jan 25 '23 03:01

mikera