Under the normal evaluation rules, (p)
would be evaluated by calling the function p
with no arguments. For example (in Common Lisp):
> (defun p ()
5)
=> P
> (p)
=> 5
Your question started by mentioning something known as 'lazy evaluation'. Common Lisp does not do this by default; it evaluates all arguments to a function from left to right. Scheme does not specify the order in which they are evaluated, just that they will be.
However, before things can be evaluated, they need to be expanded (which can mean a number of things in lisp), which gives lisp the ability to control the order of evaluation. For example, p
could be a macro. In this case, the normal evaluation rules don't necessarily apply. Again, in Common Lisp:
> (defmacro p ()
(print "I'm being expanded!") ; print on expansion
(terpri) ; new line.
`(progn (print "I'm being evaluated!") ; print on evaluation
(terpri)
5))
=> P
This is entered the Read Evaluate Print Loop. The expression is read, then expanded, evaluated, then printed.
> (p)
I'm being expanded!
I'm being evaluated!
=> 5
To stop the expansion being evaluated, let's stick it in a lambda. You will notice that it still prints the expansion message.
> (defvar foo (lambda () (p)))
I'm being expanded!
=> COMPILED FUNCTION #<LAMBDA>
Now we call it, and the form is evaluated.
> (funcall foo) ; call the function
I'm being evaluated!
=> 5
You can expand a macro invocation on its own.
> (macroexpand-1 '(lambda () (p)))
I'm being expanded!
=> (lambda () (progn (print "I'm being evaluated!")
(terpri)
5))
Languages such as Haskell have lazy evaluation by default. In the passage you quoted, SICP has you imagine a lazy version of lisp. For such a lisp to work, and only evaluate things that are needed, it would need to not just blindly expand and evaluate everything until it arrives at a value (see the discussion of the substitution model in SICP), but to just expand things and only evaluate things when it is specifically asked for their values. You can compare this to the example above, where we expanded the macro P
in the body of a lambda expression, forcing the evaluation with FUNCALL
when we wanted the value. Later in SICP, you will use a similar technique to implement lazy lists.
As I say, Haskell does this sort of thing automatically, and it's not hard to imagine a lisp that does the same (though, currently no popular ones do). I suppose I went on a bit of a tangent, given the actual question in the book, but hopefully you'll have got a bit of an idea of how to tell what is evaluated and when, and the difference it can make.