SICP Exercise 3.22

Question

Instead of representing a queue as a pair of pointers, we can build a queue as a procedure with local state. The local state will consist of pointers to the beginning and the end of an ordinary list. Thus, the make-queue procedure will have the form

(define (make-queue)
  (let ((front-ptr  )
        (rear-ptr  ))
    definitions of internal procedures
    (define (dispatch m) )
    dispatch))

Complete the definition of make-queue and provide implementations of the queue operations using this representation.

Answer

(define (make-queue)
  (let ((front-ptr '())
        (rear-ptr '()))
    (define (empty-queue?)
      (null? front-ptr))
    (define (front-queue)
      (if (empty-queue?)
          (error "FRONT called with an empty queue")
          (car front-ptr)))
    (define (set-front-ptr! i)
      (set! front-ptr i))
    (define (set-rear-ptr! i)
      (set! rear-ptr i))
    (define (insert-queue! i)
      (define new-pair (cons i '()))
      (cond ((empty-queue?)
             (set-front-ptr! new-pair)
             (set-rear-ptr! new-pair)
             (cons front-ptr rear-ptr))
            (else
             (set-cdr! rear-ptr new-pair)
             (set-rear-ptr! new-pair)
             (cons front-ptr rear-ptr))))
    (define (delete-queue!)
      (cond ((empty-queue?)
             (error "DELETE! called with an empty queue"))
            (else
             (set-front-ptr! (cdr front-ptr))
             (cons front-ptr rear-ptr))))
    (define (dispatch m)
      (cond ((eq? m 'insert-queue!) insert-queue!)
            ((eq? m 'delete-queue!) delete-queue!)
            (else
             (error "UNKNOWN METHOD -- make-queue"))))
    dispatch))

(define (insert-queue! q i) ((q 'insert-queue!) i))
(define (delete-queue! q) ((q 'delete-queue!)))

Test:

(define q1 (make-queue))
(insert-queue! q1 'a)
(insert-queue! q1 'b)
(insert-queue! q1 'c)
(delete-queue! q1)
(delete-queue! q1)
(delete-queue! q1)

Results:

((a) a)
((a b) b)
((a b c) c)
((b c) c)
((c) c)
(() c)