Why does
((fn[x] (eval (symbol "x"))) 1)
blow up Unable to resolve symbol: x in this context?
I expected it to behave just like
((fn[x] x) 1)
and evaluate to 1.
(How) Can the former be fixed to return 1 using eval?
eval does not use the lexical scope where it is called (as introduced by fn, let, or loop), it only sees vars as mapped via the current namespace (bound to the var *ns*).
Introducing a lexical binding into an eval context will involve wrapping the form in a let manually, or using undocumented implementation dependent host interop to find and provide lexical bindings to the eval context.
An example of wrapping in a let manually (this will only work when x is something readable by the Clojure reader):
user=> (def x 0)
#'user/x
user=> (let [x 42] (eval 'x)) ; gets the global value of x, not local
0
user=> (let [x 42] (eval (list 'let ['x (list 'quote x)] 'x))) ; manually getting the local
42
Related
Here's a working minimal example showing how Clojure can handle non-namespaced symbols:
(defmacro simple-macro [s]
(name `~s))
(str "And the answer is "
(simple-macro v1))
Now I'd like to do something more complicated. Inspired by this example:
(defn typical-closure []
(let [names (atom [])]
(fn [arg] (swap! names conj arg) #names)))
(def Q (typical-closure))
(Q 1)
(Q 2)
;; [1 2]
I now want to define a similar closure to take the names of undefined variables.
(defn take-names-fun []
(let [names (atom [])]
#((swap! names conj (simple-macro %)) (deref names))))
(def P (take-names-fun))
(P v1)
But this doesn't work as hoped; I get the error:
Unable to resolve symbol: v1 in this context
Is there a way to fix this so that we can add the name "v1" to the list of names defined above?
I tried using a macro instead (inspired by a syntax trick on page 21 of "Mastering Clojure Macros")... but this answer on ask.clojure.org says it doesn't make sense to define a closure over an atom in a macro.
(defmacro take-names-macro []
(let [names (atom [])]
`(fn [~'x] (swap! ~names conj (simple-macro ~'x)) (deref ~names))))
(def R (take-names-macro))
And indeed, I get another error here:
Can't embed object in code, maybe print-dup not defined:
However, there is no such restriction for using atoms inside defn. Maybe at the end of the day I need to put my symbols in a namespace...?
Not quite sure what it is that you're ultimately trying to accomplish.
But, since P is a function, it will always evaluate its arguments. So, if you pass it an undefined symbol, you'll get the error you got. Instead, you have to create a macro so that you can quote the undefined symbol (to stop the evaluation of the argument) and then pass that to P. Here is an example that does that.
user> (defn take-names-fun []
(let [names (atom [])]
(fn [arg] (swap! names conj (name arg)))))
#'user/take-names-fun
user> (def P (take-names-fun))
#'user/P
user> (defmacro PM [s] `(P (quote ~s)))
#'user/PM
user> (PM v1)
["v1"]
user> (PM v2)
["v1" "v2"]
user>
You might find the article on Evaluation in Clojure helpful.
#dorab's answer is nice.
But you could also tell yourself: "When entering undefined variables into a function, I have to quote them to avoid evaluation of them!"
So, after:
(defn typical-closure []
(let [names (atom [])]
(fn [arg] (swap! names conj arg) #names)))
(def Q (typical-closure))
Do:
user=> (Q 'v1)
[v1]
user=> (Q 'v2)
[v1 v2]
user=> (Q 3)
[v1 v2 3]
user=> (Q 'v4)
[v1 v2 3 v4]
user=>
In this way you don't need the macro and you can alternate between evaluated and not-evaluated arguments (undefined symbols).
So with the way fn's are written in clojure there is unfortunately no way to get the name of the var being passed as a param from within the fn body.. Someone with more experience with the clojure src may be able to explain better why that is, my initial guess would be that it has something to do with keeping thread local scopes isolated and lazy.
But there's absolutely nothing stopping you from writing a macro that wraps other macros using your closure idea!
Here's an example of how something like that may be written:
https://stackoverflow.com/a/11857444
user=> (def v-1 "this is v1")
user=> (def v-2 "this is v2")
user=> (defmacro m [v] (symbol (str "v-" v)))
user=> (m 1)
"this is v1"
user=> (m 2)
"this is v2"
user=> (let [i 2] (m i))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: v-i in this context, compiling:(NO_SOURCE_PATH:73:12)
Can I write a macro let both
(m 2)
and
(let [i 2] (m i))
get "this is v2" ?
This is possible without a macro:
(defn m [v] (var-get (resolve (symbol (str "v-" v)))))
(m 1) ;; => "This is v1"
(let [i 2] (m i)) ;; => "This is v2"
You can use a macro too if you want:
(defmacro m [v] `#(resolve (symbol (str "v-" ~v))))
A plain function seems much more likely to be what you want.
First, though, to address the original question, if you wanted to insist on using a macro, macros are regular functions that happen to be called at compile time, so you can look up a Var using its symbolic name and obtain its value using deref just like you could at (your application's, as opposed to your macro's) runtime:
(defmacro var-value [vsym] #(resolve vsym))
(def foo 1)
(var-value foo)
;= 1
(macroexpand-1 '(var-value foo))
;= 1
Note that the above 1 is the actual macroexpansion here. This is different to
(defmacro var-value [vsym] `#(resolve ~vsym))
in that the latter expands to a call to resolve, and so the lookup given that implementation is postponed to your app's runtime.
(macroexpand-1 '(var-value foo))
;= (clojure.core/deref (clojure.core/resolve foo))
So this code will just be inlined wherever you call the macro.
Of course the macro could also expand to a symbol – e.g.
(defmacro prefixed-var [suffix]
`(symbol (str "v-" ssuffix)))
will produce expansions like v-1 (for (prefixed-var 1)) etc.
Going back to the subject of the suitability of macros here, however, if you use a macro, all the information that you need to produce your expansion must be available at compile time, and so in general you cannot use the values of let / loop locals or function arguments in your expansion for the fundamental reason that they don't have any fixed value at compile time.1
Thus the cleanest approach would probably be to wrap a resolve call in defn and call the resulting function – although of course to know for sure, we'd need to know what problem you were trying to solve by introducing a macro that performs a Var lookup.
1 Except if statically assigned constant values, as in the example given in the question text; I'm assuming you're thinking of using runtime values of locals in general, not just those that whose initialization expressions are constant literals.
I have a question regarding how to define functions/macros which call other macros or special forms but where one of the symbols passed in needs to be dynamic.
The simplest version of this question is described below:
We can define variables using def
(def x 0)
But what if we wanted the name x to be determined programmatically so that we could do the equivalent of?
(let [a 'b]
(our-def a 3)) => user/b
We could try to define a function
(defn defn2 [sym val]
(def sym val))
However it does not do what we want
(def2 'y 1) => #'user/sym
At first it seems like a macro works (even though it seems like it would be unnecessary)
(defmacro def3 [sym val]
`(def ~sym ~val))
(def3 z 2) => user/z
but it is just superficial, because we're really right back where we started with regular def.
(let [a 'b]
(def3 a 3)) => user/a
I can do it if I use eval, but it doesn't seem like eval should be necessary
(defn def4 [sym val]
(eval `(def ~sym ~val)))
(let [a 'b]
(def4 a 4)) => user/b
If there are other built-in commands that could achieve this particular example, they are not really what I am looking for since def is just to show a particular example. There are macros more complicated than def that I might want to call and not have to worry about how they were internally implemented.
First: The right way to do this is to use macro that starts with def... since this is the way people have been doing defs and is of little surprise to the user.
To answer you question: Use intern:
(def foo 'bar)
(intern *ns* foo :hi)
(pr bar) ;; => :hi
(intern *ns* foo :hi2)
(pr bar) ;; => :hi2
If you want to use macros do this:
(def z 'aa)
(defmacro def3 [sym val]
`(def ~(eval sym) ~val))
(def3 z 2)
(pr aa) ;; => 2
The following code compiles fine:
(intern *ns* 'a 1) ;#'user/a
(intern *ns* 'b (+ a 1)) ;#'user/b
It also compiles in a do:
(do
(intern *ns* 'c 1)
(intern *ns* 'd (+ c 1)))
However compilation fails in a let (or any other binding form I have tried, including fn):
(let []
(intern *ns* 'e 1)
(intern *ns* 'f (+ e 1)))
;CompilerException java.lang.RuntimeException: Unable to resolve symbol: ‘e in this context, compiling:(NO_SOURCE_PATH:2:5)
It looks like the interns are not performed in this case until after the let completes. My only work around instead of using locals is to mutate atoms or use alter-var-root.
Why doesn't intern work inside let, et al. the same way it does in do? Is there a way to force the intern to complete inside a let so that the above example compiles? (BTW, macros are not an option as I want to access runtime information in my binding form using ns-map)
You can't write that, because only do gets the special treatment causing its subforms to each be compiled and evaluated in order, rather than all compiled at once and then all evaluated. But really, this is a weird way to do what you are trying to do: these manual calls to intern are quite unusual. Why not simply put locals into your let, and then intern whichever ones you want to keep? let has exactly the property you need, in that previously-defined symbols are visible in the next binding.
(let [e 1, f (+ e 1)]
(intern *ns* 'e e)
(intern *ns* 'f f))
Another answer by #amalloy answers the "why" part of the question and suggests a workaround. If, for some reason, it is still important to refer to a value of an interned var, resolve function can be used:
(let []
(intern *ns* 'e 1)
(intern *ns* 'f (+ #(resolve 'e) 1)))
;; => #'user/f
e
;; => 1
f
;; => 2
Functions with closures seem to break when used with eval.
(eval {:fn (let [x "foo"] (fn [] "x"))})
;=> {:fn #<user$eval14716$fn__14717 user$eval14716$fn__14717#1ddd735>}
(eval {:fn (let [x "foo"] (fn [] x))})
;=> IllegalArgumentException No matching ctor found for class user$eval14740$fn__14741
; clojure.lang.Reflector.invokeConstructor (Reflector.java:166)
I don't really know enough about Clojure (or closure) to know if this is a bug or something which intentionally isn't allowed - can anyone shed some light on this?
Edit: Just to be clear, I'm talking specifically about the way eval handles function objects. AFAIK eval is actually designed to work with java objects, including functions; the example given on the clojure website - (eval (list + 1 2 3)) - passes a function object into eval.
Cloure's eval does not perfectly support function objects. It's not necessarily even closures that cause the problem.
For example, this did not work in Clojure 1.0.0:
(eval {:fn (fn [x] x)})
But this did:
(eval (fn [x] x))
The first example got fixed. The following also works:
(eval (let [x "foo"] (fn [] x)))
But the following still does not work:
(eval {:fn (let [x "foo"] (fn [] x))})
I can't pin it down to a single line in the compiler, but it's something about how literal objects (clojure.lang.Compiler$ObjExpr I think) get handled by eval in different contexts: e.g. at the "top" of an expression versus inside another data structure.
In general, I think, you cannot rely on being able to eval function objects in Clojure, regardless of whether or not they are closures. It happens to work for some simple examples, mostly to simplify the explanation of things like (eval (list + 1 2)). Macros should always return literal source code as data structures, not compiled functions.
Try quoting your argument to eval:
(eval '{:fn (let [x "foo"] (fn [] x))})
;=> {:fn #<user$eval345$fn__346 user$eval345$fn__346#17b6dd83>}
((:fn *1))
;=> "foo"
This is not a bug. The equivalent of (eval (list + 1 2 3)) with a "closure" is (eval (list fn [] "foo")), not (eval (fn [] "foo")).
And (eval (list fn [] "foo")) => Can't take value of a macro: #'clojure.core/fn, again indicating that you're not supposed to do things like that (and there's no need for it anyway).