djechlin
djechlin

Reputation: 60788

How does lisp decide whether to evaluate a list or use it as data?

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

Answers (2)

djechlin
djechlin

Reputation: 60788

There are two fundamental lisp concepts to understand here:

  1. The difference between reading and evaluating
  2. Special forms
  3. Symbols

Read v. evaluate

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:

  1. Read: the read form "161" is converted to the object that is the number 161 in Lisp.
  2. Evaluate: the number 161 is a self-evaluating form. So 161 evaluates to 161.
  3. Print: The print representation of the number 161 is "161". So this number is printed.
  4. Loop: Prompt for input again.

Symbols: not self-evaluating forms

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:

  1. The s-expression "abc" is read
  2. It is the read form for the symbol abc, so that object is created.
  3. The symbol abc evaluates to its variable, but, it holds no variable currently ("void" is used), so it errors

The special form setq will set the symbol to point to a variable. More on that below.

Special forms

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

Macros also do not evaluate their arguments, but a full discussion is probably not necessary to the original question.

Upvotes: 6

Rainer Joswig
Rainer Joswig

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

  • function calls like (* a b)
  • special forms like (let ((a 1)) a). These forms are usually built-in and can't be extended by a user.
  • macro forms like (defun foo () nil)
  • plus whatever the Lisp dialect else provides...

The identifier, which is the first element in the list, tells us how to evaluate the form.

Upvotes: 1

Related Questions