Reputation: 60788
If you write something like (+ 2 3)
, the +
is treated as a function, and an error occurs if +
does not have any function definition associated with it.
If you write something like (let (a b c))
, (a b c)
is read as data.
How does lisp decide?
Upvotes: 0
Views: 532
Reputation: 60788
There are two fundamental lisp concepts to understand here:
Reading is the act of converting text into lisp objects. Lisp objects such as numbers and lists have what is called a read form, which is a textual representation that can be read into an object. It is usually the same as the print form. If you are coming from a language such as Java, toString() gives the print form of an object. There is no equivalent concept for reading, because Lisp has the interesting and powerful property that Lisp source code is a lisp object.
It is important to note that reading is not the same as evaluating, although many objects self-evaluate. For instance, a number is an object that when evaluated, returns itself. It would be more common to say many forms self-evaluate, but you should remember that a "form" in context usually is synonymous to "lisp object," with the implication that the object will be evaluated.
It may be useful to consider what happens when we run a simple program in a REPL. Recall "REPL" stands for "Read, evaluate, print, loop", and Lisp is the language where the difference between these steps really stands clear.
Consider the list program:
161
When you run it in a REPL the result is the following:
161
What happens here is the following:
The read form of a symbol will be text like abc
. Symbols evaluate to the variable they hold. Let's run the program abc
in a REPL:
abc
This program in fact produces the error:
eval-last-sexp-1: Symbol's value as variable is void: abc
What happens here is:
The special form setq
will set the symbol to point to a variable. More on that below.
From here, Lisp works like most languages. Calling (+ 1 (+ 2 3))
will do the same thing as plus(1, plus(2,3))
would in an imperative language with a plus function. The whole expression will be red to build up the list object (+ 1 (+ 2 3 ))
, which is a list of three elements +
, 1
and the list (+2 3)
. Then, the outer +
, being a function call, will cause the interpreter to evaluate the objects 1
, which is self-evaluating, and (+ 2 3)
, which will ultimately evaluate to 5. Then +
will take the two evaluated objects, 1
and 5
, and add them, and return 6
.
However, Lisp has what are called special forms. Special forms may skip the evaluate step and just use the original object. For instance, setq
is a special form that evaluates the second argument, but not the first.
(setq a (+ 2 3))
Will not evaluate the symbol "a", but will take the symbol "a" and assign it to what (+ 2 3)
evaluates to, namely, the number 5. Then, calling
a
in a REPL will print 5
.
So to answer the original question... "let" is a special form so its arguments are not evaluated immediately :)
Macros also do not evaluate their arguments, but a full discussion is probably not necessary to the original question.
Upvotes: 6
Reputation: 139311
If you write something like (let (a b c)), (a b c) is read as data.
Not really. Everything is read the same. The Lisp form is first read. Fully. Evaluation comes later. The Evaluation makes the difference.
A LET
expression is a special form and the form is evaluated according to special rules.
See the Emacs Lisp manual: Parts of let Expression.
Lisp has
(* a b)
(let ((a 1)) a)
. These forms are usually built-in and can't be extended by a user.(defun foo () nil)
The identifier, which is the first element in the list, tells us how to evaluate the form.
Upvotes: 1