Variable scope + eval in Clojure

前端 未结 1 1203
栀梦
栀梦 2020-11-28 14:23

In Clojure,

(def x 3)
(eval \'(prn x))

prints 3, whereas

(let [y 3]
   (eval \'(prn y)))

and

<         


        
相关标签:
1条回答
  • 2020-11-28 14:49

    1.:

    The reason this doesn't work is (more or less) given on the page you linked:

    It is an error if there is no global var named by the symbol […]
    

    And:

    […]

    1. A lookup is done in the current namespace to see if there is a mapping from the symbol to a var. If so, the value is the value of the binding of the var referred-to by the symbol.

    2. It is an error.

    eval evaluates forms in an empty (null in CL-lingo) lexical environment. This means, that you cannot access lexical variable bindings from the caller's scope. Also, binding creates new bindings for existing vars, which is why you cannot use it "by itself", without having declared or defed the variables you try to bind. Besides, lexical variables (at least in CL, but I would be surprised if this wasn't the case for Clojure) already ceased to exist at runtime – They are translated to addresses or values.

    See also my older post about this topic.

    2.:

    So, you have to use dynamic variables. You can avoid the explicit def, but you still at least need to declare them (which defs var names without bindings):

    user=> (declare ^:dynamic x)
    #'user/x
    user=> (binding [x 10] (eval '(prn x)))
    10
    nil
    

    By the way: I suppose you know why you need eval, and that its use is considered evil when other solutions would be appropriate.

    0 讨论(0)
提交回复
热议问题