Why does the expression
('+ 10 20)
evaluate to 20
? This is realy bizarre to me! I would have expected to give an error, because the first element of the list, '+
i not a thing that can be evaluated!
Why does the expression
('+ 10 20)
evaluate to 20
? This is realy bizarre to me! I would have expected to give an error, because the first element of the list, '+
i not a thing that can be evaluated!
This is pretty much an FAQ with Clojure, for good or bad. So '+
is shorthand for (quote +)
which evaluates to the symbol +
. Symbols (and keywords) can be treated as functions and look themselves up in their argument, so ('+ 10 20)
is essentially (get 10 '+ 20)
and that's the not-found
arity of get
so if the "collection" 10
does not include the symbol '+
then it will return the third argument, 20
.
You might expect associative lookup against 10
to fail and throw an exception but there are a lot of situations in Clojure where lookup will return nil
(or the not-found
version) because it's beneficial from a nil
-punning point of view and is part of what leads to idiomatic Clojure.
Some functions do perform that sort of argument checking: (contains? 10 '+)
will throw an exception, for example, whereas both (get 10 '+)
and (get '+ 10)
will both return nil
.
It's probably also worth noting that the following throws an exception:
user=> ('+ 10 20 30)
Execution error (ArityException) at user/eval39476 (REPL:1).
Wrong number of args (3) passed to: clojure.lang.Symbol
You asked if the "value of a list with quoted first argument in clojure is the last argument" and the answer is no, this is very specifically a two-argument function invocation, because of the above logic: you can't "call" a symbol with 3 args, only with 1 or 2.
Worth noting the difference here for the 0 args case:
user=> ('+)
Execution error (ArityException) at user/eval39478 (REPL:1).
Wrong number of args (0) passed to: clojure.lang.Symbol
user=> (+)
0
The first case is a symbol lookup -- which requires at least a collection to look itself up in -- whereas the second case is a function invocation (of clojure.core/+
) with zero arguments, which returns the identity value of +
in the same way that (*)
returns 1
.