mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-18 21:29:18 +02:00
195 lines
5.5 KiB
Scheme
195 lines
5.5 KiB
Scheme
;;;; Implementation of list-queue SRFI
|
|
|
|
;;; This definition is from Chibi's SRFI-1 implementation.
|
|
|
|
(define (last-pair ls) (if (null? (cdr ls)) ls (last-pair (cdr ls))))
|
|
|
|
;;; This definition of map! isn't fully SRFI-1 compliant, as it
|
|
;;; handles only unary functions. You can use SRFI-1's definition
|
|
;;; if you want.
|
|
|
|
(define (map! f lis)
|
|
(let lp ((lis lis))
|
|
(if (pair? lis)
|
|
(begin
|
|
(set-car! lis (f (car lis)))
|
|
(lp (cdr lis))))))
|
|
|
|
;;; The list-queue record
|
|
;;; The invariant is that either first is (the first pair of) a list
|
|
;;; and last is the last pair, or both of them are the empty list.
|
|
|
|
(define-record-type <list-queue> (raw-make-list-queue first last) list-queue?
|
|
(first get-first set-first!)
|
|
(last get-last set-last!))
|
|
|
|
;;; Constructors
|
|
|
|
(define make-list-queue
|
|
(case-lambda
|
|
((list)
|
|
(if (null? list)
|
|
(raw-make-list-queue '() '())
|
|
(raw-make-list-queue list (last-pair list))))
|
|
((list last)
|
|
(raw-make-list-queue list last))))
|
|
|
|
(define (list-queue . objs)
|
|
(make-list-queue objs))
|
|
|
|
(define (list-queue-copy list-queue)
|
|
(make-list-queue (list-copy (get-first list-queue))))
|
|
|
|
;;; Predicates
|
|
|
|
(define (list-queue-empty? list-queue)
|
|
(null? (get-first list-queue)))
|
|
|
|
;;; Accessors
|
|
|
|
(define (list-queue-front list-queue)
|
|
(if (list-queue-empty? list-queue)
|
|
(error "Empty list-queue")
|
|
(car (get-first list-queue))))
|
|
|
|
(define (list-queue-back list-queue)
|
|
(if (list-queue-empty? list-queue)
|
|
(error "Empty list-queue")
|
|
(car (get-last list-queue))))
|
|
|
|
;;; Mutators (which carefully maintain the invariant)
|
|
|
|
(define (list-queue-add-front! list-queue elem)
|
|
(let ((new-first (cons elem (get-first list-queue))))
|
|
(if (list-queue-empty? list-queue)
|
|
(set-last! list-queue new-first))
|
|
(set-first! list-queue new-first)))
|
|
|
|
(define (list-queue-add-back! list-queue elem)
|
|
(let ((new-last (list elem)))
|
|
(if (list-queue-empty? list-queue)
|
|
(set-first! list-queue new-last)
|
|
(set-cdr! (get-last list-queue) new-last))
|
|
(set-last! list-queue new-last)))
|
|
|
|
(define (list-queue-remove-front! list-queue)
|
|
(if (list-queue-empty? list-queue)
|
|
(error "Empty list-queue"))
|
|
(let* ((old-first (get-first list-queue))
|
|
(elem (car old-first))
|
|
(new-first (cdr old-first)))
|
|
(if (null? new-first)
|
|
(set-last! list-queue '()))
|
|
(set-first! list-queue new-first)
|
|
elem))
|
|
|
|
(define (list-queue-remove-back! list-queue)
|
|
(if (list-queue-empty? list-queue)
|
|
(error "Empty list-queue"))
|
|
(let* ((old-last (get-last list-queue))
|
|
(elem (car old-last))
|
|
(new-last (penult-pair (get-first list-queue))))
|
|
(if (null? new-last)
|
|
(set-first! list-queue '())
|
|
(set-cdr! new-last '()))
|
|
(set-last! list-queue new-last)
|
|
elem))
|
|
|
|
(define (list-queue-remove-all! list-queue)
|
|
(let ((result (get-first list-queue)))
|
|
(set-first! list-queue '())
|
|
(set-last! list-queue '())
|
|
result))
|
|
|
|
;; Return the next to last pair of lis, or nil if there is none
|
|
|
|
(define (penult-pair lis)
|
|
(let lp ((lis lis))
|
|
(cond
|
|
;((null? lis) (error "Empty list-queue"))
|
|
((null? (cdr lis)) '())
|
|
((null? (cddr lis)) lis)
|
|
(else (lp (cdr lis))))))
|
|
|
|
;;; The whole list-queue
|
|
|
|
|
|
;; Because append does not copy its back argument, we cannot use it
|
|
(define (list-queue-append . list-queues)
|
|
(list-queue-concatenate list-queues))
|
|
|
|
(define (list-queue-concatenate list-queues)
|
|
(let ((result (list-queue)))
|
|
(for-each
|
|
(lambda (list-queue)
|
|
(for-each (lambda (elem) (list-queue-add-back! result elem)) (get-first list-queue)))
|
|
list-queues)
|
|
result))
|
|
|
|
(define list-queue-append!
|
|
(case-lambda
|
|
(() (list-queue))
|
|
((queue) queue)
|
|
(queues
|
|
(for-each (lambda (queue) (list-queue-join! (car queues) queue))
|
|
(cdr queues))
|
|
(car queues))))
|
|
|
|
; Forcibly join two queues, destroying the second
|
|
(define (list-queue-join! queue1 queue2)
|
|
(set-cdr! (get-last queue1) (get-first queue2)))
|
|
|
|
(define (list-queue-map proc list-queue)
|
|
(make-list-queue (map proc (get-first list-queue))))
|
|
|
|
(define list-queue-unfold
|
|
(case-lambda
|
|
((stop? mapper successor seed queue)
|
|
(list-queue-unfold* stop? mapper successor seed queue))
|
|
((stop? mapper successor seed)
|
|
(list-queue-unfold* stop? mapper successor seed (list-queue)))))
|
|
|
|
(define (list-queue-unfold* stop? mapper successor seed queue)
|
|
(let loop ((seed seed))
|
|
(if (not (stop? seed))
|
|
(list-queue-add-front! (loop (successor seed)) (mapper seed)))
|
|
queue))
|
|
|
|
(define list-queue-unfold-right
|
|
(case-lambda
|
|
((stop? mapper successor seed queue)
|
|
(list-queue-unfold-right* stop? mapper successor seed queue))
|
|
((stop? mapper successor seed)
|
|
(list-queue-unfold-right* stop? mapper successor seed (list-queue)))))
|
|
|
|
(define (list-queue-unfold-right* stop? mapper successor seed queue)
|
|
(let loop ((seed seed))
|
|
(if (not (stop? seed))
|
|
(list-queue-add-back! (loop (successor seed)) (mapper seed)))
|
|
queue))
|
|
|
|
(define (list-queue-map! proc list-queue)
|
|
(map! proc (get-first list-queue)))
|
|
|
|
(define (list-queue-for-each proc list-queue)
|
|
(for-each proc (get-first list-queue)))
|
|
|
|
;;; Conversion
|
|
|
|
(define (list-queue-list list-queue)
|
|
(get-first list-queue))
|
|
|
|
(define (list-queue-first-last list-queue)
|
|
(values (get-first list-queue) (get-last list-queue)))
|
|
|
|
(define list-queue-set-list!
|
|
(case-lambda
|
|
((list-queue first)
|
|
(set-first! list-queue first)
|
|
(if (null? first)
|
|
(set-last! list-queue '())
|
|
(set-last! list-queue (last-pair first))))
|
|
((list-queue first last)
|
|
(set-first! list-queue first)
|
|
(set-last! list-queue last))))
|
|
|