Aivar
Aivar

Reputation: 7052

Why does Clojure allow (eval 3) although 3 is not quoted?

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 quoteas 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

Answers (4)

mobyte
mobyte

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

  1. any object meant to be evaluated.
  2. a symbol, a compound form, or a self-evaluating object.
  3. (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

Rainer Joswig
Rainer Joswig

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

amalloy
amalloy

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

Diego Sevilla
Diego Sevilla

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:

  1. When you hit enter, the expression is evaluated. It contain a normal function call (eval) and some arguments.
  2. The arguments are evaluated. The first argument contains a quote, which tells the reader to produce what is after the quote (the actual (+ 3 4) list).
  3. There are no more arguments, and the actual function call is evaluated. This means calling the eval function with the list (+ 3 4) as argument.
  4. The eval function does the same steps again, finding the normal function + and the arguments, and applies it, obtaining the result.

Upvotes: 6

Related Questions