SICP section 3.3 - modelling with mutable data (incomplete)

This is the second section whose content I haven’t been too enthused about (the first being section 2.5). This, rather coincidentally , is also the second section whose exercises I’ve left incomplete (the first being section 2.5 ).

(defineq1(make-queue))(insert-queue!q1'a); `front-ptr` points to the only pair '(a); `rear-ptr` points to the only pair '(a)(insert-queue!q1'b); `front-ptr` points to the start of the queue '(a b); `rear-ptr` points to the last pair in the queue '(b)(delete-queue!q1); `front-ptr` points to the `cdr` of the queue '(a b), i.e. '(b); `rear-ptr` points to the last pair in the queue '(b)(delete-queue!q1); `front-ptr` points to the `cddr` of the queue '(a b), i.e. '(); `rear-ptr` points to the last pair in the queue '(b)

Defining the print-queue procedure is simple, we just display the car of the queue:

(define(print-queuequeue)(display(front-ptrqueue))(newline))

Exercise 3.22

(define(make-queue)(let((front-ptr'())(rear-ptr'()))(define(queue)(consfront-ptrrear-ptr))(define(set-front-ptr!item)(set!front-ptritem))(define(set-rear-ptr!item)(set!rear-ptritem))(define(empty-queue?)(null?front-ptr))(define(front-queue)(if(empty-queue?)(error"FRONT called with an empty queue"(queue))(carfront-ptr)))(define(insert-queue!item)(let((new-pair(consitem'())))(cond((empty-queue?)(set-front-ptr!new-pair)(set-rear-ptr!new-pair)(queue))(else(set-cdr!rear-ptrnew-pair)(set-rear-ptr!new-pair)(queue)))))(define(delete-queue!)(cond((empty-queue?)(error"DELETE! called with an empty queue"(queue)))(else(set-front-ptr!(cdrfront-ptr))(queue))))(define(print-queue)(displayfront-ptr)(newline))(define(dispatchm)(cond((eq?m'front-queue)front-queue)((eq?m'insert-queue!)insert-queue!)((eq?m'delete-queue!)delete-queue!)((eq?m'print-queue)print-queue)(else(error"Unknown request: MAKE-QUEUE"m))))dispatch))

Exercise 3.23

I must admit - this exercise had me stumped. I’ve implemented many a singly and doubly linked list in C, but I just couldn’t quite grasp how to do the same in Scheme. It’s probably because I was being thick.

After much staring at other people’s solutions, I’ve adopted the approach of having each pair hold a backward-pointer to the previous pair in the queue.

Heavily annotated code in an effort to un-stump myself:

(define(make-deque)(let((front-ptr'())(rear-ptr'()))(define(deque)(consfront-ptrrear-ptr))(define(set-front-ptr!item)(set!front-ptritem))(define(set-rear-ptr!item)(set!rear-ptritem))(define(empty-deque?)(null?front-ptr))(define(front-deque)(if(empty-deque?)(error"FRONT called with an empty deque"(deque))(caarfront-ptr)))(define(rear-deque)(if(empty-deque?)(error"REAR called with an empty deque"(deque))(caarrear-ptr)))(define(front-insert-deque!item)(let((new-pair(cons(consitem'())'())))(cond((empty-deque?)(set-front-ptr!new-pair)(set-rear-ptr!new-pair)(deque))(else; Set the backward-pointer of the first pair; in the queue to the new pair(set-cdr!(carfront-ptr)new-pair); Add the new pair to the front of the queue; by appending the front pointer to the new pair(set-cdr!new-pairfront-ptr); Set the front pointer to the new pair, as it; is now the first pair in the queue(set-front-ptr!new-pair)(deque)))))(define(rear-insert-deque!item)(let((new-pair(cons(consitem'())'())))(cond((empty-deque?)(set-front-ptr!new-pair)(set-rear-ptr!new-pair)(deque))(else; Set the backward-pointer on the new pair to the; current last pair in the queue(set-cdr!(carnew-pair)rear-ptr); Add the new pair to the rear of the queue; via the rear pointer(set-cdr!rear-ptrnew-pair); Set the rear pointer to the new pair, as it; is now the last pair in the queue(set-rear-ptr!new-pair)(deque)))))(define(front-delete-deque!)(cond((empty-deque?)(error"FRONT-DELETE! called with an empty deque"(deque)))((null?(cdarrear-ptr))(set-front-ptr!'()))(else; Move the front pointer "forward" one pair(set-front-ptr!(cdrfront-ptr)); Set the backward-pointer of the new front pair to '()(set-cdr!(carfront-ptr)'())(deque))))(define(rear-delete-deque!)(cond((empty-deque?)(error"REAR-DELETE! called with an empty deque"(deque)))((null?(cdarrear-ptr))(set-front-ptr!'()))(else; Move the rear pointer "backward" one pair(set-rear-ptr!(cdarrear-ptr)); Set the forward-pointer of the new rear pair to '()(set-cdr!rear-ptr'())(deque))))(define(print-deque); The `car` of a pair holds the data,; the `cdr` holds the backward-pointer(display(mapcarfront-ptr))(newline))(define(dispatchm)(cond((eq?m'front-deque)front-deque)((eq?m'rear-deque)rear-deque)((eq?m'front-insert-deque!)front-insert-deque!)((eq?m'rear-insert-deque!)rear-insert-deque!)((eq?m'front-delete-deque!)front-delete-deque!)((eq?m'rear-delete-deque!)rear-delete-deque!)((eq?m'print-deque)print-deque)(else(error"Unknown request: MAKE-DEQUE"m))))dispatch))