While most operations in Scheme are procedure calls, there are a few other kinds of expressions you need to know about, which behave differently. They are called special forms.
Procedure calls and special forms are syntactically similar--both
are a sequence of syntactic units between parentheses, e.g.,
(foo bar baz)
. They are semantically very different, however,
which is why you need to know the special forms, and not mistake
them for procedures.
If the first thing after the left parentheses is a keyword that
names a special form, like define
or set!
, Scheme
does something special for that kind of expression. If it's
not, Scheme recognizes the expression in parentheses as a procedure
call, and evaluates it in the usual way for procedure calls.
(This is why special forms are called "special forms"---Scheme recognizes some kinds of compound expressions as needing special treatment, rather than just being procedure calls.)
You've already seen two of the five or six important special forms,
define
and the assignment operator set!
.
Notice that set!
isn't a procedure, because
its first argument is not really an expression to be evaluated in the
normal way, to get a value to pass as an argument. It's the name of a
place to put a value. (e.g., if we say (set! a b)
, we
get the value of b
, and put it into the storage named by
a
.)
Likewise, define
treats its first argument specially--the name
of a variable or procedure isn't an expression that is evaluated and
passed to define
---it's just a name, and you're telling define
to allocate some storage and use that name for it.
Other special forms we'll see include
if
, cond
, and case
and the sort-circuiting logical operators and
and
or
;
let
and
its variants letrec
and let*
;
let
and do
;
quote
and quasiquote
, which let you write complex
data structures as textual literals in your code, and
lambda
, which creates new procedures in a very
useful way.
There is also a few very special special forms, define-syntax
,
which let you define your own special forms as "macros."