A stack is a container for a sequence of values that can be extended only by adding a new value at the beginning (which is conventionally called the ``top'' of the stack) and from which a value can be removed only at the beginning. A stack is thought of as a container that persists even as values are added to or removed from the sequence.
Sometimes stacks are also considered to be subject to the restriction that only the value at the beginning of the sequence can be inspected. However, usage varies; in other applications, the entire stack can be inspected and printed and the size of the stack can be determined (not just whether it is empty or non-empty, but exactly how many members it contains).
In Scheme, it is natural to represent a stack by a procedure that maintains the sequence of values as a list held in a private storage location, inaccessible from outside the procedure, and to enforce the condition that this list can be accessed and modified only in the specified ways by submitting the access and modification requests as arguments to the procedure that represents the stack. The following definition (adapted from program 12.12 in Scheme and the art of programming, by George Springer and Daniel P. Friedman [Cambridge, Massachusetts: The MIT Press, 1989], page 398), shows how such a private datum can be allocated and used to implement stacks.
Notice that the variable(define make-stack (lambda () (let ((stk '())) (lambda (message . args) (case message ;; If the message is empty?, the stack returns #t if its ;; storage location contains the null object, #f if it ;; contains a non-empty list. ((empty?) (null? stk)) ;; The push! message should be accompanied by an extra ;; argument -- the value to be pushed onto the stack. This ;; value is simply added to the front of the list in the ;; private storage location. ((push!) (set! stk (cons (car args) stk))) ;; If the message is top, the stack returns the first ;; element of the list in private storage, or signals an ;; error if that list is empty. ((top) (if (null? stk) (error "top: The stack is empty.") (car stk))) ;; If the message is pop!, the stack returns the first ;; element of the list in private storage after removing ;; that element from that list. ((pop!) (if (null? stk) (error "pop!: The stack is empty.") (let ((result (car stk))) (set! stk (cdr stk)) result))) ;; Comment out any of the following operations that are not ;; wanted in a particular application of stacks. ;; When it receives the size message, the stack reports the ;; number of elements in the list in private storage. ((size) (length stk)) ;; If the message is nth, there should be an extra argument ;; -- the (zero-based) position of the item desired, or in ;; other words the number of values on the stack that ;; precede the one to be returned. ((nth) (list-ref stk (car args))) ;; When it receives the print message, the stack displays ;; the elements of the list in private storage, each ;; followed by a space, then starts a new line. ((print) (for-each (lambda (element) (display element) (display " ")) stk) (newline)) ;; It is an error to send the stack any other message. (else (error "stack: unrecognized message")))))))
stk
is
allocated outside of the lambda-expression for the procedure being
returned; this ensures that it will persist between calls to that
procedure. Notice also, however, that stk
is given a
different value each time make-stack
is invoked. If the
let-expression that binds stk
enclosed the outer
lambda-expression as well as the inner one, all the procedures returned by
make-stack
would provide access to the same storage location,
and all stacks would be one stack.
This document is available on the World Wide Web as
http://www.math.grin.edu/~stone/events/scheme-workshop/stacks.html