123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- ;;; This is a purely functional FIFO (first in first out) queue data structure
- ;;; in GNU Guile. This queue implementation makes use of a front stack and back
- ;;; stack, which are exchanged, when the front stack is empty and one tries to
- ;;; access the head of the queue.
- ;;; Adapted from https://programmingpraxis.com/2013/11/08/two-stacks-make-a-queue/
- ;;; Changes I made to adapt the code to GNU Guile:
- ;;; - translation to GNU Guile (Scheme)
- ;;; - binding renamings for better readability,
- ;;; - imports of required modules
- ;;; - bug fixes (endless loop in case of dequeue-ing from empty queue)
- ;;; - some error handling
- ;;; - comments (there were none)
- ;;; - docstrings (there were none)
- (use-modules
- (ice-9 match)
- ;; SRFI-8 for receive form
- (srfi srfi-8))
- ;; A stack is implemented using a list.
- (define empty-stack '())
- (define (push stack x)
- "Push an element onto the stack by cons-ing it to the list, which is used as
- stack."
- (cons x stack))
- (define (pop stack)
- "Pop the top element of the stack, returning both, the top element and the
- updated stack."
- (values (car stack) (cdr stack)))
- ;; Checking whether a stack is empty is simply checking whether a list is empty.
- (define empty-stack? null?)
- (define (transfer src dst)
- "Transfer all element of one stack to the other stack, reversing their order,
- as we can only pop elements, which are on top of a stack and only push elements
- onto elements of a stack."
- (cond [(empty-stack? src) dst]
- [else
- (receive (x xs) (pop src)
- ;; Transfer the rest of the elements. Recur.
- (transfer xs (push dst x)))]))
- ;; Creating an empty queue means creating an empty front stack and empty back
- ;; stack.
- (define empty-queue (cons empty-stack empty-stack))
- (define (enqueue queue elem)
- "Enqueue an element x into the given queue."
- ;; First, via match, separate the front stack and back stack of the queue, so
- ;; that we can push the new element onto one of the stacks.
- (match queue
- ;; A queue is the pair of back stack and front stack. Push the element onto
- ;; the back stack and make a new queue.
- [(back-stack . front-stack)
- (cons (push back-stack elem)
- front-stack)]
- [_
- (error "enqueue got something else than a queue:" queue)]))
- (define (dequeue queue)
- "Dequeue the head of the queue."
- ;; First, via match, separate the front stack and back stack of the queue.
- (cond
- [(queue-empty? queue)
- (error "cannot dequeue from empty queue")]
- [else
- (match queue
- [(back-stack . front-stack)
- (cond
- ;; If the front stack is empty, transfer all elements from the back stack to
- ;; the front stack and then dequeue.
- [(empty-stack? front-stack)
- (dequeue
- (cons empty-stack
- (transfer back-stack front-stack)))]
- ;; Otherwise pop an element from the front stack and return both, the element
- ;; and the updated queue.
- [else
- (receive (elem updated-front-stack) (pop front-stack)
- (values elem (cons back-stack updated-front-stack)))])]
- [_
- (error "dequeue got something else than a queue:" queue)])]))
- (define (queue-empty? queue)
- "Check whether a queue is empty, by checking whether both stacks are empty."
- (and (null? (car queue))
- (null? (cdr queue))))
|