Reputation: 7052
I'm learning Clojure and trying to understand reader, quoting, eval and homoiconicity by drawing parallels to Python's similar features.
In Python, one way to avoid (or postpone) evaluation is to wrap the expression between quotes, eg. '3 + 4'
. You can evaluate this later using eval
, eg. eval('3 + 4')
yielding 7
. (If you need to quote only Python values, you can use repr
function instead of adding quotes manually.)
In Lisp you use quote
or '
for quoting and eval
for evaluating, eg. (eval '(+ 3 4))
yielding 7
.
So in Python the "quoted" stuff is represented by a string, whereas in Lisp it's represented by a list which has quote
as first item.
My question, finally: why does Clojure allow (eval 3)
although 3
is not quoted? Is it just the matter of Lisp style (trying to give an answer instead of error wherever possible) or are there some other reasons behind it? Is this behavior essential to Lisp or not?
Upvotes: 8
Views: 393
Reputation: 3752
To answer this question we need to look at eval
definition in lisp. E.g. in CLHS there is definition:
Syntax: eval form => result*
Arguments and Values: form - a form.
results - the values yielded by the evaluation of form.
Where form
is
- any object meant to be evaluated.
- a symbol, a compound form, or a self-evaluating object.
- (for an operator, as in
<<operator>> form'') a compound form having that operator as its first element.
A quote form is a constant form.''
In your case number "3" is self-evaluating object
. Self-evaluating object
is a form that is neither a symbol nor a cons is defined to be a self-evaluating object
. I believe that for clojure we can just replace cons
by list
in this definition.
In clojure only lists
are interpreted by eval
as function calls. Other data structures and objects are evaluated as self-evaluating objects.
'(+ 3 4)
is equal to (list '+ 3 4)
. '
(transformed by reader to quote
function) just avoid evaluation of given form. So in expression (eval '(+ 3 4))
eval
takes list data structure ('+ 3 4)
as argument.
Upvotes: 2
Reputation: 139411
What should 3
evaluate to? It makes the most sense that Lisp evaluates a number to itself. Would we want to require numbers to be quoted in code? That would not be very convenient and extremely problematic:
Instead of
(defun add-fourtytwo (n)
(+ n 42))
we would have to write
(defun add-fourtytwo (n)
(+ n '42))
Every number in code would need to be quoted. A missing quote would trigger an error. That's not something one would want to use.
As a side note, imagine what happens when you want to use eval
in your code.
(defun example ()
(eval 3))
Above would be wrong. Numbers would need to be quoted.
(defun example ()
(eval '3))
Above would be okay, but generating an error at runtime. Lisp evaluates '3
to the number 3. But then calling eval
on the number would be an error, since they need to be quoted.
So we would need to write:
(defun example ()
(eval ''3))
That's not very useful...
Numbers have be always self-evaluating in Lisp history. But in earlier Lisp implementations some other data objects, like arrays, were not self-evaluating. Again, since this is a huge source of errors, Lisp dialects like Common Lisp have defined that all data types (other than lists and symbols) are self-evaluating.
Upvotes: 3
Reputation: 92127
Other answers have explained the mechanics, but I think the philosophical point is in the different ways lisp and python look at "code". In python, the only way to represent code is as a string, so of course attempting to evaluate a non-string will fail. Lisp has richer data structures for code: lists, numbers, symbols, and so forth. So the expression (+ 1 2)
is a list, containing a symbol and two numbers. When evaluating a list, you must first evaluate each of its elements.
So, it's perfectly natural to need to evaluate a number in the ordinary course of running lisp code. To that end, numbers are defined to "evaluate to themselves", meaning they are the same after evaluation as they were before: just a number. The eval
function applies the same rules to the bare "code snippet" 3
that the compiler would apply when compiling, say, the third element of a larger expression like (+ 5 3)
. For numbers, that means leaving it alone.
Upvotes: 4
Reputation: 29021
The short answer would be that numbers (and symbols, and strings, for example) evaluate to themselves. Quoting instruct lisp (the reader) to pass unevaluated whatever follows the quote. eval
then gets that list as you wrote it, but without the quote, and then evaluates it (in the case of (eval '(+ 3 4))
, eval
will evaluate a function call (+
) over two arguments).
What happens with that last expression is the following:
eval
) and some arguments.(+ 3 4)
list).eval
function with the list (+ 3 4)
as argument.eval
function does the same steps again, finding the normal function +
and the arguments, and applies it, obtaining the result.Upvotes: 6