Variables
2010-12-11
Introduction
Variables in Scheme can be used to hold values of any type. One variable can hold values of different types during its lifetime. This part of the tutorial describes how variables are declared and used in Scheme.
Define
One way to declare variables in Scheme is using define
. It takes two arguments: the name of the variable to define, and its value.
define
adds the variable to the top-level environment, so that it can be seen from anywhere.
Define can also be used for defining functions. The following syntax can be used for this:
(define (name arguments) body)
Here, name is the name of the function you are defining, arguments are zero or more argument names, and body is a sequence of expressions. The function must be called with values for each of the arguments, and will evaluate the expressions in the body, returning the value of the last expression. The arguments are variables that are only visible inside the function, and they will eclipse any variables outside the function that have the same name.
An example:
; A simple variable
(define foo 12)
; A function with no arguments that references foo
(define (print-foo) (display foo) (newline))
; A function that prints the sum of its two arguments
(define (print-sum a b) (display (+ a b)) (newline))
; A function that prints its argument
(define (print-arg foo) (display foo) (newline))
(print-foo)
(print-sum foo 1)
(print-arg "bar")
(print-foo)
The output of this program is:
12 13 bar 12
Evidently, foo has the value "bar"
inside print-arg
, but 12
outside of it. This is because
foo inside and foo outside are really two different variables. They just happen to have the same name.
Let
Another way of declaring variables is by means of let
. Contrary to define
, let
does not add variables to
the top-level environment. Instead, variables are only visible inside the body of let
. It has the following syntax:
(let (declarations) body)
The declarations part consists of declarations of the form (symbol value)
. The body contains
normal Scheme expressions. They will be evaluated in order, and let
will return the value of the last expression evaluated. Let's see some
examples:
(let ((a 1) (b 2)) (+ a b)) ; => 3
; Tell the user something he already knows:
(let ((a "You typed: ") (b (read-line)))
(display (string-append a b))
(newline))
Let*
Note that variables defined by let
are defined only in the body. You might expect the following code to return 3:
(let ((a 1) (b (+ a 1))) (+ a b))
More likely, an error will be signaled in the definition of b, because a is not defined yet. That is, unless a
had been defined outside the let
, in which case b will get the value of that definition, plus one. You can rewrite the code above to
actually return 3 by using a variant of let
called let*
. It works like let
, but defines the variables in order of
appearance. a will be defined and bound to 1 when the definition for b is processed, so b gets the value 2, the body is
evaluated, and the value 3 is returned.
Letrec
Yet another variant of let
is letrec
. It differs from the others in that it first defines all variables, and then
starts assigning values. This means that you can reference any of the other variables in the definition of a variable. This can be used for defining mutually
recursive functions (functions that call one another). See Binding constructs in the
Report for an example.