insertion-sort, for sorting a list of numbers:
Each of these procedures is recursive, and the Scheme interpreter keeps track of various bindings of the paramter
(define insert-item (lambda (item ls) (if (or (null? ls) (<= item (car ls))) (cons item ls) (cons (car ls) (insert-item item (cdr ls))) ) ) ) (define insertion-sort (lambda (ls) (if (null? ls) ls (insert-item (car ls) (insertion-sort (cdr ls))) ) ) )
ls. For example, if
trace-defineis used for
insertion-sortand the procedure is run on the list
(3 1 4 1 5), the following output results:
Here, the binding of the parameter
> (insertion-sort '(3 1 4 1 5)) |(insertion-sort (3 1 4 1 5)) | (insertion-sort (1 4 1 5)) | |(insertion-sort (4 1 5)) | | (insertion-sort (1 5)) | | |(insertion-sort (5)) | | | (insertion-sort ()) | | | () | | |(5) | | (1 5) | |(1 4 5) | (1 1 4 5) |(1 1 3 4 5) (1 1 3 4 5)
lsis like writing the variable and its value on a three-by-five card and filing it away in a box of similar cards. Successive procedure calls introduce a new card with the new value on it, and this value is paper-clipped to the front of the card for the old binding. During the procedure call, the new binding takes precedence over the old one, since its card is on top; but when the procedure returns, the top card is removed and thrown away, and the old binding is still in place and in force. The Scheme interpreter maintains an internal table of variables and values that is similar to such a card box. In Scheme, this table of variables and values is called an ``environment.''
let-expression produces a similar effect.
> (define str "original binding") > str "original binding" > (let ((str "new binding")) str) "new binding" > str "original binding"Explain how this output is achieved.
> (define str "original binding") > (let ((str "second binding")) (display "2: ") (display str) (newline) (let ((str "third binding")) (display "3: ") (display str) (newline) (let ((str "fourth binding")) (display "4: ") (display str) (newline) (let ((str "fifth binding")) (display "5: ") (display str) (newline)) (display "4: ") (display str) (newline)) (display "3: ") (display str) (newline)) (display "2: ") (display str) (newline))Run this code, describe the output, and explain how that result is achieved.
In recognition of this difference in the way the bindings are treated,
variables that are either predefined or bound by top-level definitions are
sometimes called global variables, while procedure parameters and
variables that appear in the binding lists of
are local variables. (A top-level redefinition of a variable
changes its value ``globally'' -- through all subsequent uses of that
binding -- whereas other rebindings change the value only ``locally,''
within a procedure body or the body of a
definestatement establishes a new variable and gives it a value. Subsequent uses of
defineat Scheme's top level change that value. Within a procedure, an assignment or
set!expression changes a binding, as shown in the following example:
> (define ch #\A) > ch #\A > (define ch #\B) > ch #\B > (set! ch #\C) > ch #\C > (set! ch #\D) > ch #\D > (let ((ch #\E)) (display "0: ") (display ch) (newline) (set! ch #\F) (display "1: ") (display ch) (newline) (set! ch #\G) (display "2: ") (display ch) (newline) (set! ch (integer->char 114)) (display "3: ") (display ch) (newline) (set! ch "I'm tired of this game.") (display "4: ") (display ch) (newline)) 0: E 1: F 2: G 3: r 4: I'm tired of this game. > ch #\D
chis both a global and a local variable. Be sure you can explain which value is changed when and why.
It is an error to assign a new value to a variable that is not bound at all -- if there is no card in the box for a certain variable, there's nothing to erase. (Chez Scheme will step in and create a global variable for you if you commit this error, but most implementations of Scheme are not so considerate.)
Similarly, the operations
append! change various parts of a list.
insertion-sortprocedures return a newly sorted list, which is separate from the original list. If we always want to sort data stored in a global variable
data, then we can use
set!to update such data as follows:
First, we define a simple, parameterless procedure:
Then, we call this procedure whenever the
(define sort-data (lambda () (set! data (insertion-sort data)) ) )
datalist is to be sorted.
sort-data, run the following sequence of operations:
Explain the results you obtain.
(define data '(3 1 6 -8 4)) data (sort-data) data
cdrof the list, as shown in the following variation of
(define insertion-sort (lambda (ls) (letrec ((sort-data (lambda (lst) (if (null? lst) lst (insert-item (car lst) (sort-data (cdr lst))))))) (let ((result (sort-data ls))) (set-car! ls (car result)) (set-cdr! ls (cdr result)) result ) ) ) )
insertion-sort, run the following sequence of operations:
(define first '(3 1 6 -8 4)) first (define second '(5 3 7 9 2 6 1 8)) second (insertion-sort first) (insertion-sort second) first second
insertion-sortproduces its output; that is, hypothesize how is the parameter changed.
letstatement; what happens if this line is omitted?
(define insertion-sort (lambda (ls) (letrec ((sort-data (lambda (lst) (if (null? lst) lst (insert-item (car lst) (sort-data (cdr lst))))))) (let ((result (sort-data ls))) (set! ls result) ls ) ) ) )
firstpoints to the designated list:
insertion-sort is called, parameter
made to point to the same list:
sort-data is called, a new ordered list is
returned, and variable
result is set to designate this new
set! expression changes
ls to point to the
The final line
ls returns this new list as the result of the
procedure. However, as the diagram shows, the variable
still points to the original, unchanged list.
insertion-sortfrom step 4 to clarify further why the code with
set-cdr!works correctly -- even though the latest version with
(set! ls result)does not change the global variable.
This document is available on the World Wide Web as