(module queue mzscheme
  (provide empty empty? insert insert* remove first)
  
  (define-struct queue (front back) (make-inspector))
  
  (define empty (make-queue '() '()))
  
  (define (empty? Q)
    (and (null? (queue-front Q))
         (null? (queue-back Q))))
  
  (define (insert Q x)  
    (make-queue (queue-front Q) 
                (cons x (queue-back Q))))
  
  (define (insert* Q elms)
    (if (null? elms)
        Q
        (insert* (insert Q (car elms)) (cdr elms))))
                           
  
  (define (remove Q)
    (cond
     [(and (null? (queue-front Q)) (null? (queue-back Q)))
      (error "remove: The queue is empty")]
     [(null? (queue-front Q))
      (remove (make-queue (reverse (queue-back Q)) '()))]
     [else
      (values (car (queue-front Q)) 
              (make-queue (cdr (queue-front Q)) (queue-back Q)))]))
  
  (define (first Q)
    (cond
     [(empty? Q)
      (error "first: The queue is empty")]
     [(null? (queue-front Q))
      (first (make-queue (reverse (queue-back Q)) '()))]
     [else
      (car (queue-front Q))]))
  )