I suppose you are trying to implement a queue. This can be done in several ways, but if you want both the insert and the remove operation to be performed in constant time, O(1), you must keep a reference to the front and the back of the queue.
You can keep these references in a cons cell or as in my example, wrapped in a closure.
The terminology push
and pop
are usually used when dealing with stacks, so I have changed these to enqueue
and dequeue
in the code below.
(define (make-queue)
(let ((front '())
(back '()))
(lambda (msg . obj)
(cond ((eq? msg 'empty?) (null? front))
((eq? msg 'enqueue!)
(if (null? front)
(begin
(set! front obj)
(set! back obj))
(begin
(set-cdr! back obj)
(set! back obj))))
((eq? msg 'dequeue!)
(begin
(let ((val (car front)))
(set! front (cdr front))
val)))
((eq? msg 'queue->list) front)))))
make-queue
returns a procedure which wraps the state of the queue in the variables front
and back
. This procedure accepts different messages which will perform the procedures of the queue data structure.
This procedure can be used like this:
> (define q (make-queue))
> (q 'empty?)
#t
> (q 'enqueue! 4)
> (q 'empty?)
#f
> (q 'enqueue! 9)
> (q 'queue->list)
(4 9)
> (q 'dequeue!)
4
> (q 'queue->list)
(9)
This is almost object oriented programming in Scheme! You can think of front
and back
as private members of a queue class and the messages as methods.
The calling conventions is a bit backward but it is easy to wrap the queue in a nicer API:
(define (enqueue! queue x)
(queue 'enqueue! x))
(define (dequeue! queue)
(queue 'dequeue!))
(define (empty-queue? queue)
(queue 'empty?))
(define (queue->list queue)
(queue 'queue->list))
Edit:
As Eli points out, pairs are immutable by default in PLT Scheme, which means that there is no set-car!
and set-cdr!
. For the code to work in PLT Scheme you must use mutable pairs instead. In standard scheme (R4RS, R5RS or R6RS) the code should work unmodified.