I have the following two test cases in Clojure, one destructuring a vector, and one destructuring a list:
user=> ((fn [[a op b]] (op a b)) [1 + 2])
3
user=> ((fn [[a op b]] (op a b)) '(1 + 2))
2
Why is the symbol + evaluated in the first test case but not the second? Is the quote recursive, so in the second test case op
is really 'op
?
You are correct that the single quote '
(equivalent of the function quote
) will return a list of symbols, suppressing evaluation. However, since symbols cannot start with a number, the PersistentList
'(1 + 2)
will contain a java.lang.Long
, a clojure.lang.Symbol
, and a java.lang.Long
.
When you invoke the function given by the Symbol
+
(which is possible because Symbol
extends AFn
which itself implements IFn
, and overrides the invoke
function), this gets executed:
public Object invoke(Object obj, Object notFound) {
return RT.get(obj, this, notFound);
}
Since you executed (op a b)
, or ('+ 1 2)
, obj
is 1
, notFound
is 2
, and this
is the Symbol
+
in the call to clojure.lang.RT
's get
method, which looks like this:
static public Object get(Object coll, Object key, Object notFound){
if(coll instanceof ILookup)
return ((ILookup) coll).valAt(key, notFound);
return getFrom(coll, key, notFound);
}
Again, coll
is the Long
1, key is the Symbol
+
, and notFound is the Long
2.
So when a function is called, it's being looked up in a collection. Since 1
is not a collection, the value notFound
, or 2
, is being returned.
As a visual of a ('+ 5 10)
example, in a debugger: