tags:

views:

860

answers:

3

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?

+6  A: 

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

pmf
+4  A: 

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
Christian Vest Hansen
+6  A: 

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.

Brian Carper