If I have a namespace symbol e.g. 'clojure.core or a path to a clojure source file how can I get all symbols that are new to the namespace, i.e. not :refer-ed or interned in another namespace?
Those symbols would come from top level defs (and defns) but also inside let bindings and such. My goal is to analyze a namespace and walk the tree effectively doing a find-replace on certain symbols based on a predicate.
Edit: I'm not just looking for top level vars, I'm looking for any symbol. If there's a function with a let binding in it I'm looking for symbol that was bound.
The comments you've received tell you how to get the top-level refs, however there's only one way to get the local let bindings, and that's to access the &env special form which is only available inside a macro:
(defmacro info []
(println &env))
(def a 5)
(let [b a] (let [c 8] (info)))
;{ b #object[clojure.lang.Compiler$LocalBinding 0x72458346 clojure.lang.Compiler$LocalBinding#72458346],
; c #object[clojure.lang.Compiler$LocalBinding 0x5f437195 clojure.lang.Compiler$LocalBinding#5f437195]}
To get a map of local names to local values, for example:
(defmacro inspect []
(->> (keys &env)
(map (fn [k] [`'~k k]))
(into {})))
(let [b a] (let [c 8] (inspect)))
; => {b 5, c 8}
Related
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
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
Let's take that Clojure code:
(defn ^{:test-1 "meta-test-1"} fn-key-1
[x]
(eval nil))
(defn ^{:test-2 "meta-test-2"} fn-key-2
[x]
(eval nil))
(def some-map {fn-key-1 "test-1"
fn-key-2 "test-2"})
As you can see, the keys of my map are Symbols that refers to functions. I don't thing there is anything special there.
As you can see, when defining the map the keys of my map are Symbols that refers to functions. However, when they are read by the reader, then they get resolved to the function objects.
Now, what I want to do is to iterate over my some-map map to get the meta-data for each of the keys.
I was thinking doing this that way:
(defn some-fn
[m]
(doseq [[fn-key value] m]
(println (meta fn-key))))
However, what is being printed here is nil. This is expected since the meta-data is defining the symbol, and not the function. So, there is no meta-data attached to the function and it is why nil is being returned/printed.
So this lead to a question: is it possible to get the symbol that refers to my function "fn-key" in that context?
In that doseq loop, it appears that fn-key is a function and not the symbol of that function. What I need is a way to get the symbol of that function such that I can use (meta (get-symbol fn-key)).
Question Resolution
This question got resolved by defining the functions that way:
(def fn-key-1
(with-meta (fn [x] (eval nil)) {:foo "bar"}))
(def fn-key-2
(with-meta (fn [x] (eval nil)) {:foo "bar"}))
Revision of the Resolution
I revised the solution above to make it cleaner. In fact, if you were to type fn-key-1 in the REPL, you were to get an anonymous function reference such as #< clojure.lang.AFunction$1#15ab1764>. The problem with that is that it make things difficult to debug when you don't know what is being evaluated. To solve this issue, I changed the two function definitions to use this syntax, which resolve this issue:
(def fn-key-1 ^{:foo "bar"} (fn [x] (eval nil)))
(def fn-key-2 ^{:foo "bar"} (fn [x] (eval nil)))
Now, if we type fn-key-1 then we will get something like #<core$foo user.core$foo#66e37466> instead. At least, we have the namespace & symbol signature of this function object.
(def some-map {#'fn-key-1 "test-1"
#'fn-key-2 "test 2"})
fn-key-1 is resolved by the reader to the function object (which has no metadata to query). #'fn-key-1 resolves to the var itself, and holds the metadata.
Consider
(defn f ^{:foo "bar"} [x] (* x x))
and
(defn g #^{:foo "bar"} [x] (* x x))
Both compile and run.
I have two questions: first, why do (meta f) and (meta g) produce only nil? I would have expected them to produce {:foo "bar"}; i.o.w., am I just completely out to lunch on metadata and have I defined some kind of garbage out there?
Second, what is the difference between the two syntaces for the metadata? It looks like the second one is a "tagged literal," something to do with edn, the extended data notation, but I can't quite noodle it out without some more context or examples.
The #^ metadata reader macro was replaced with ^ in clojure 1.2. While there is currently no difference between the two, the old form is deprecated and you should be using ^ exclusively.
The metadata literal should come before the item it is to be attached to:
(defn ^{:foo "bar"} f [x] (* x x))
Another thing to keep in mind is that the metadata in the above definition isn't attached to the function, it is attached to the var that refers to the function. You can get the metadata of the f var with:
(meta (var f))
Or using the var reader macro:
(meta #'f)
I'm looking for the ability to have the REPL print the current definition of a function. Is there any way to do this?
For example, given:
(defn foo [] (if true "true"))
I'd like to say something like
(print-definition foo)
and get something along the lines of
(foo [] (if true "true"))
printed.
An alternative to source (which should be available via clojure.repl/source when starting a REPL, as of 1.2.0. If you're working with 1.1.0 or lower, source is in clojure.contrib.repl-utils.), for REPL use, instead of looking at functions defined in a .clj file:
(defmacro defsource
"Similar to clojure.core/defn, but saves the function's definition in the var's
:source meta-data."
{:arglists (:arglists (meta (var defn)))}
[fn-name & defn-stuff]
`(do (defn ~fn-name ~#defn-stuff)
(alter-meta! (var ~fn-name) assoc :source (quote ~&form))
(var ~fn-name)))
(defsource foo [a b] (+ a b))
(:source (meta #'foo))
;; => (defsource foo [a b] (+ a b))
A simple print-definition:
(defn print-definition [v]
(:source (meta v)))
(print-definition #'foo)
#' is just a reader macro, expanding from #'foo to (var foo):
(macroexpand '#'reduce)
;; => (var reduce)
You'll want to import the repl namespace, and use the source function from it:
(ns myns
(:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)
=> (foo [] (if true "true"))
nil
Though this wouldn't work in the REPL, only where the function is defined in a .clj file on the classpath. Which doesn't answer your question, then: you'd need to have a defn that stores, in the metadata of the fn it defines, the source of the function. Then you'd write a function that recalls that bit of metadata. That shouldn't be terribly difficult.
Clojure doesn't have a decompiler, so that means there's no way to get at the source of an arbitrary function unless it was a defn loaded from disk. However, you can use a neat hack called serializable-fn to create a function that has its source form stored in its metadata: http://github.com/Seajure/serializable-fn
The defsource answer is very similar to this, but this solution works with arbitrary fns, not just top-level defns. It also makes fns print prettily at the repl without a special printing function.
In clojure 1.2's REPL, the source function is immediately available. You can use it this way:
$ java -cp clojure.jar clojure.main
Clojure 1.2.0
user=> (source slurp)
(defn slurp
"Reads the file named by f using the encoding enc into a string
and returns it."
{:added "1.0"}
([f & opts]
(let [opts (normalize-slurp-opts opts)
sb (StringBuilder.)]
(with-open [#^java.io.Reader r (apply jio/reader f opts)]
(loop [c (.read r)]
(if (neg? c)
(str sb)
(do
(.append sb (char c))
(recur (.read r)))))))))
nil
user=>
A few other functions are also automatically imported into the REPL's user namespace from the clojure.repl library. See the API doc here.
However, as pointed out in other answers here, you can't use source as is to print back functions you have defined in the REPL.
I asked exactly this question on the Clojure mailing list recently and the answers included overriding parts of the REPL to stash the input (and output) away for future reference as well as an override of defn to store the source in metadata (which you could then easily retrieve in the REPL).
Read the thread on the Clojure mailing list