You can define a variable in Scheme using a define
:
(define my-variable 5)
This tells Scheme to allocate space for my-variable
, and initialize
that storage with the value 5
.
In Scheme, you always give a variable an initial value, so there's no such thing as an uninitialized variable or an unininitialized variable error.
Scheme values are always pointers to objects, so when we use the literal
5
, Scheme interprets that as meaning a pointer to the object
5
. Numbers are objects you can have pointers to, just like any
other kind of data structure. (Actually, most Scheme implementations
use a couple of tricks to avoid pointer overheads on numbers, but that
doesn't show up at the language level. You don't have to be aware
of it.)
After the above definition, we can draw the resulting situation like this:
+-------+ foo | *---+--->5 +-------+
The define
expression does three things:
foo
in the current scope. (I'll talk about scoping
a lot, later.)
foo
to a particular piece of memory, so that we can refer to that
storage by the name foo
.
These three things happen when you define variables in other languages, too. In Scheme we have names for all three.
In the picture, the box represents the fact that Scheme has allocated
storage for a variable. The name foo
beside the box means
that we've given that storage the name foo
. The arrow says
that the value in the box is a pointer to the integer object 5
.
(Don't worry about how the integer object is actually represented. It
doesn't really matter.)
You can define new procedures with define
, too:
(define (two-times x) (+ x x))
Here we've defined a procedure named two-times
, which takes one
argument, x
. It then calls the addition procedure +
to add the argument value to itself, and returns the result of the
addition.
Notice the sytnactic difference between the variable definition and the procedure definition: for a procedure definition, there are parentheses around the name, and the argument name(s) follow that inside the parentheses.
This resembles the way the procedure is called. Consider the procedure
call expression (two-times 5)
, which returns 10
; it
looks like the definition's (two-times x)
, except that we've put
the actual argument 5 in place of the formal parameter
x
.
Here's a bit of programming language terminology you should know: the arguments you pass to a procedure are sometimes called actual parameters. The argument variables inside the procedure are called formal parameters---they stand for whatever is actually passed to the procedure at run time. "Actual" means what you actually pass to the procedure, and "formal" means what you call that on the inside of the procedure. Usually, I'll just talk about "arguments," but that's the same thing as "actual parameters." Sometimes I'll talk about "argument variables," and that's the same thing as "formal parameters."
You can define a procedure of zero arguments, but you still have to put parentheses around the procedure name, to make it clear that you're defining a procedure. You put parentheses around its name when you call it, too, to make it clear that it's a procedure call.
For example, this is a definition of a variable whose initial value
is 15
:
(define foo 15)
but this is a definition of a procedure foo
which returns
15
when called.
(define (foo) 15)
+-------+ foo | *---+--->#<procedure> +-------+
This picture shows that when you define a procedure, you're really
defining a variable whose value happens to be a (pointer to
a) procedure. For now, you don't really have to worry about that.
The main thing to know is that now you can call the procedure
by the name foo
. For example, the procedure call expression
(foo)
will return 15
, because all the body of the
procedure does is return the value 15
.
Usually, we indent procedure definitions like this, with the body starting a new line, and indented a few characters:
(define (foo) 15)
This makes it clearer that it's a procedure definition.