I have a symbol "a" bound to a function:
(defn a []
(println "Hello, World"))
user=> a
#<user$a__292 user$a__292#97eded>
user=> (a)
Hello, World
nil
Then I use syntax-quote, it "resolves the symbol in the current context, yielding a fully-qualified symbol", according to Clojure documentation. But why can't I use it the same way as unqualified symbol?
user=> `a
user/a
user=> (`a)
java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol (NO_SOURCE_FILE:0)
Second question: if I have a symbol in a list, why can't I evaluate it the same way as if I would evaluate the symbol directly?
user=> (def l '(a 1 2))
#'user/l
user=> 'l
l
user=> (first l)
a
user=> ((first l))
java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol (NO_SOURCE_FILE:0)
I have a suspicion I have a fatal flaw somewhere in the fundamental understanding of how symbols work here. What is wrong with above code?
REPL = read eval print loop. Step through the read-eval process.
READ: Clojure sees the string "(`a)", parses it and ends up with a data structure. At read time, reader macros are expanded and not much else happens. In this case, the reader expands the backquote and ends up with this:
user> (read-string "(`a)")
((quote user/a))
EVAL: Clojure tries to evaluate this object. Evaluation rules vary depending on what kind of object you're looking at.
Some objects evaluate as themselves (numbers, strings, keywords etc.).
A Symbol is evaluated by resolving it in some namespace to obtain some value (usually).
A List is evaluated by macro-expanding the list until there are no macros left, then recursively evaluating the first item in the list to obtain some resulting value, then using the value of the first item in the list to decide what to do. If the first value is a special form, special stuff happens. Otherwise the first value is treated as a function and called with the values of the rest of the list (obtained by recursively evaluating all of the list's items) as parameters.
etc.
Refer to clojure.lang.Compiler/analyzeSeq in the Clojure source to see the evaluation rules for lists, or clojure.lang.Compiler/analyzeSymbol for symbols. There are lots of other evaluation rules there.
Example
Suppose you do this:
user> (user/a)
The REPL ends up doing this internally:
user> (eval '(user/a))
Clojure sees that you're evaluating a list, so it evaluates all items in the list. The first (and only) item:
user> (eval 'user/a)
#<user$a__1811 user$a__1811#82c23d>
a is not a special form and this list doesn't need to be macroexpanded, so the symbol a is looked up in the namespace user and the resulting value here is an fn. So this fn is called.
Your code
But instead you have this:
user> (eval '((quote user/a)))
Clojure evaluates the first item in the list, which is itself a list.
user> (eval '(quote user/a))
user/a
It evaluated the first item in this sub-list, quote, which is a special form, so special rules apply and it returns its argument (the Symbol a) un-evaluated.
The symbol a is the value in this case as the fn was the value up above. So Clojure treats the Symbol itself as a function and calls it. In Clojure, anything that implements the Ifn interface is callable like an fn. It so happens that clojure.lang.Symbol implements Ifn. A Symbol called as a function expects one parameter, a collection, and it looks itself up in that collection. It's meant to be used like this:
user> ('a {'a :foo})
:foo
This is what it tries to do here. But you aren't passing any parameters, so you get the error "Wrong number of args passed to: Symbol" (it expects a collection).
For your code to work you'd need two levels of eval. This works, hopefully you can see why:
user> (eval '((eval (quote user/a))))
Hello, world
user> ((eval (first l)))
Hello, world
Note that in real code, using eval directly is usually a really bad idea. Macros are a better idea by far. I'm only using it here for demonstration.
Look in Compiler.java in the Clojure source to see how this all plays out. It's not too hard to follow.
Using a Symbol as a function is not the same thing as evaluating it. Symbols-as-functions work the same way as keywords-as-functions. Like this:
user=> (declare a)
#'user/a
user=> (def a-map {'a "value"})
#'user/a-map
user=> ('a a-map)
"value"
user=>
This is not how you would normally use a symbol. They are more commonly used for looking up vars in a namespace, and when generating code in a macro.
To break down the layers of indirection, let's define "x" as 1 and see what happens:
user=> (def x 1)
#'user/x
Using def, we have created a "var." The name of the var is the symbol user/x. The def special form returns the var itself to the repl, and this is what we can see printed. Let's try and get a hold of that var:
user=> #'x
#'user/x
The #' syntax is a reader macro that says "give me the var referred to by the following symbol." And in our case, that symbol is "x". We got the same var back as before. Vars are pointers to values, and can be dereferenced:
user=> (deref #'x)
1
But the var needs to be found before it can be dereferenced. This is where the callability of symbols come into play. A namespace is like a map, where the symbols are keys and vars are the values, and when we plainly name a symbol, we implicitly look up its var in our namespace. Like this:
user=> ('x (.getMappings *ns*))
#'user/x
Although, in reality, it is probably more like this:
user=> (.findInternedVar *ns* 'x)
#'user/x
And now we have come full circle on the journey of the unquoted symbol:
user=> (deref (.findInternedVar *ns* 'x))
1
user=> x
1
The two are not entirely equal, though. Because the evaluator does this for all symbols, including deref and *ns*.
The thing about quoting is that you essentially bypass this whole mechanism, and just get the plain symbol back. Like the #' reader macro get plain vars back, the ` and ' reader macros will get plain symbols back, with or without a namespace qualification respectively:
user=> 'x
x
user=> `x
user/x
user=> (def l '(a 1 2))
user=> ((first l))
Turn this into:
user=> (def l `(~a 1 2))
The ~ here resolves the symbol a to its corresponding var, and the backtick makes unquoting work.
In general, you must understand the difference between vars (which are bound to something) and symbols (which are never bound to anything).
I'll try to explain it (in the hope that my exaplanation does not confuse you further):
user=> (def v "content")
#'user/content
-> defines a var in the current namespace under the symbol 'v (fully qualified 'user/v, assuming this is the current namespace), and binds it (the var, not the symbol) to the object "content".
user=> v
"content"
-> resolves v to the var, and gets the bound value
user=> #'v
#'user/v
-> resolves to the var itself
user=> 'v
v
-> does not resolve anything, just a plain symbol (unfortunately, the REPL does not indicate this, printing 'v as v)
user=> `v
user/v
-> as you already quoted, resolves to the symbol in the current context (namespace), but the result is still a symbol (fully qualified), not the var user/v
user=> '(v)
(v)
-> plain quoting, does not resolve anything
user=> `(v)
(user/v)
-> syntax-quote, same as quoting, but resolves symbols to namespace-qualified symbols
user=> `(~v)
("content")
-> resolve the symbol to its var (which is implicitely dereferenced), yielding its bound object
Related
I can "generate" a def with a macro.
(defmacro my-def [my-name]
`(def ~my-name 42))
(my-def a)
a; => 42
If I try to do something similar with a list
(defmacro my-defs [my-names]
`(do
~#(for [name# my-names]
`(def ~name# 42))))
(my-defs (a b c))
(macroexpand '(my-defs (a b c))); => (do (def a 42) (def b 42) (def c 42))
It works as long as I use a literal list as input. But as soon as I want to pass in a var
(def my-list '(a b c))
(macroexpand '(my-defs my-list)); => Don't know how to create ISeq from: clojure.lang.Symbol
I struggle to access the value of my-names. I can't use ~my-names as it is already used in a unquote-splice (~#) and would lead to an "Attempt[...] to call unbound fn".
What am I missing?
Do I need to use (var-get (resolve my-names))?
Do macros in these cases need to "detect" if the passed argument is a literal value or a var and act accordingly in order to work for both?
Or is it idiomatic to use eval to avoid this?
Addressing #Alan Thompson's question "[...] why [do] you want to do this?": I have a specification (a deeply nested map) of "resources" and it would be rather handy to have a macro generate defs (records) for these resources in order to use them down the line. So I guess no reason out of the ordinary "It would DRY up things". :) At this time I found a way by wrapping my-names in an eval. The question that remains is: Is this idiomatic, or is there a better way?
generally you can't employ macro to generate code based on runtime value,
still your task doesn't require macro in clojure, since you can dynamically intern vars in namespaces:
(defn intern-vals [data]
(doseq [[var-name var-val] data]
(intern *ns* var-name var-val)))
user> (intern-vals {'some-val 10 'other-val 20})
;;=> nil
user> some-val
;;=> 10
user> other-val
;;=> 20
notice that this function interns values in the namespace it gets called from, thanks to *ns* dynamic var:
user> (ns a2)
a2> (user/intern-vals {'some-val "asd" 'other-val "xxx"})
;;=> nil
a2> some-val
;;=> "asd"
a2> user/some-val
;;=> 10
Macros play with symbols. When you call your macro with "my-names", that symbol goes straight into the macro, there's no lookup of the var as there would be in a function call. Then the macro says (for... and instead of a sequence there's a symbol!
As for what you should do... well, you may use resolve inside the macro, but then the macro will ONLY work if given a symbol.
Addressing #Alan Thompson's question "[...] why [do] you want to do
this?": I have a specification (a deeply nested map) of "resources"
and it would be rather handy to have a macro generate defs (records)
for these resources in order to use them down the line. So I guess no
reason out of the ordinary "It would DRY up things". :) At this time I
found a way by wrapping my-names in an eval. The question that remains
is: Is this idiomatic, or is there a better way?
I would make a single var that contains them all. And allow the macro caller to specify the var name they want. Thus making the macro "hygenic".
Is there any particular reason they have to be root vars?
The reason it doesn't work is the macro is passed the symbol my-list, not its value. So yes, you can eval it to find its value.
Considering that you are doing a (def my-list ...) first, why not make that the very def that declares your processed data struct? For example:
(def my-processed-set
(my-processing-macro '(a b c)))
or combining it
(defresources my-processed-resources '(a b c))
where defresources is your macro, and it binds the resultant set to the var referenced by the symbol passed in my-processed-resources
Then use them like (:resource-1 my-processed-resources)
Which brings you all the way back to just using a function.
(def my-processed-set
(my-processing-function '(a b c)))
data > functions > macros.
I want to get following results when I evaluate edit-url and (edit-url 1).
edit-url --> "/articles/:id/edit"
(edit-url 1) --> "/articles/1/edit"
Is it possible to define such a Var or something?
Now, I use following function, but I don't want to write (edit-url) to get const string.
(defn edit-url
([] "/articles/:id/edit")
([id] (str "/articles/" id "/edit")))
Thanks in advance.
If those behaviors are exactly what you want, print-method and tagged literals may be used to imitate them.
(defrecord Path [path]
clojure.lang.IFn
(invoke [this n]
(clojure.string/replace path ":id" (str n))))
(defmethod print-method Path [o ^java.io.Writer w]
(.write w (str "#path\"" (:path o) "\"")))
(set! *data-readers* (assoc *data-readers* 'path ->Path))
(comment
user=> (def p #path"/articles/:id/edit")
#'user/p
user=> p
#path"/articles/:id/edit"
user=> (p 1)
"/articles/1/edit"
user=>
)
edit-url will either have the value of an immutable string or function. Not both.
The problem will fade when you write a function with better abstraction that takes a string and a map of keywords to replace with words. It should work like this
(generate-url "/articles/:id/edit" {:id 1})
Clojure is a "Lisp 1" which means that is has a single namespace for all symbols, including both data scalars and functions. What you have written shows the functionally of both a string and a function but for a single name, which you can do in Common Lisp but not Clojure (not that a "Lisp 2" has its own inconveniences as well).
In general this type of "problem" is a non issue if you organize your vars better. Why not just make edit-url a function with variable arity? Without arguments it returns something, with arguments it returns something else. Really the possibilities are endless, even more so when you consider making a macro instead of a function (not that I'm advocating that).
Perhaps you can help me find this in the docs. I'm using pound-quote to be able to pass around unevaluated function names prior to execution. For example:
(#'cons 1 ())
;(1)
(defn funcrunner [func a b]
(func a b))
(funcrunner cons 'a ())
;(a)
(funcrunner 'cons 'a ())
'()
(funcrunner #'cons 'a ())
;(a)
#'cons
;#'clojure.core/cons
(resolve (symbol 'cons))
;#'clojure.core/cons
My guess is that this is a reader macro.
My question is (a) What is the pound quote (#') shorthand for? (b) Can you explain what it is doing? (c) Can you locate it in the docs? (d) Is it actually shorthand for for resolve and symbol functions?
PS - For those not in the US - # is also known as a 'hash' or a 'cross-hash'.
PPS - I'm aware my example makes the need for this somewhat redundant. I'm interested to know if this is completely redundant or there are specific use cases.
#' is a reader macro that expands to (var foo). What you're doing here is not passing around unevaluated functions, you're passing around vars which contain functions. The reason this works the way it does is because vars are functions that look up their contained value and call it:
user=> (defn foo [x] (+ x 10))
#'user/foo
user=> (#'foo 10)
20
user=> ((var foo) 10)
20
Notice that when I defined the function, a var was returned. It looks like what you've been doing! :)
#' is the reader macro for var. See http://clojure.org/special_forms#var and http://clojure.org/vars
(var foo) returns the var named by the symbol foo, which can hold any kind of value, including functions.
I'm expecting below that I should be able to call my function squared indirectly via the symbol function, but its not working. What am I doing wrong here:
user=> (defn squared [x] (* x x))
#'user/squared
user=> (squared 2)
4
user=> ((symbol "squared") 2)
nil
user=> ((symbol "user" "squared") 2)
nil
user=>
The symbol itself does not hold your function, the Var it names does.
This says "take the contents (# = deref) of the Var (resolve) named by the symbol (symbol) whose name is "squared" and apply it (as a function) to the argument 2:
(#(resolve (symbol "squared")) 2)
This says "take the Var named by the symbol etc.":
((resolve (symbol "squared")) 2)
Both will work, since Vars, when asked to act as a function, defer to the functions stored in them. (If you try to use a Var as a function when it is not bound to a function, an error will result.)
This says "take the symbol named "squared" and apply it as a function to the argument 2" -- note that the symbol itself is used as the function:
((symbol "squared") 2)
Now symbols can be used as functions (they implement the clojure.lang.IFn interface), but the way they act when used in this way is that they look themselves up in their argument, i.e. treat their argument as a map and perform a lookup inside it:
('foo {'foo 2})
; is equivalent to
(get {'foo 2} 'foo)
If the argument passed to a symbol is not something it makes sense to do lookups in, nil is returned.
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)