mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-18 21:29:18 +02:00
Initial file
This commit is contained in:
parent
69060ac9c0
commit
bb76834b9d
3 changed files with 328 additions and 0 deletions
12
srfi/117.sld
Normal file
12
srfi/117.sld
Normal file
|
@ -0,0 +1,12 @@
|
|||
(define-library (srfi 117)
|
||||
(import (scheme base) (scheme case-lambda))
|
||||
(export make-list-queue list-queue list-queue-copy list-queue-unfold list-queue-unfold-right)
|
||||
(export list-queue? list-queue-empty?)
|
||||
(export list-queue-front list-queue-back list-queue-list list-queue-first-last)
|
||||
(export list-queue-add-front! list-queue-add-back! list-queue-remove-front! list-queue-remove-back!)
|
||||
(export list-queue-remove-all! list-queue-set-list!)
|
||||
(export list-queue-append list-queue-append! list-queue-concatenate)
|
||||
(export list-queue-append list-queue-append! list-queue-concatenate)
|
||||
(export list-queue-map list-queue-map! list-queue-for-each)
|
||||
(include "list-queues/list-queues-impl.scm")
|
||||
)
|
214
srfi/list-queues/list-queues-impl.scm
Normal file
214
srfi/list-queues/list-queues-impl.scm
Normal file
|
@ -0,0 +1,214 @@
|
|||
;;;; Implementation of list-queue SRFI
|
||||
|
||||
;;; R7RS shims. Comment these out on an R7RS system.
|
||||
;;; I stole this code from Chibi Scheme, which is BSD-licensed.
|
||||
|
||||
(define (make-list n . o)
|
||||
(let ((default (if (pair? o) (car o))))
|
||||
(let lp ((n n) (res '()))
|
||||
(if (<= n 0) res (lp (- n 1) (cons default res))))))
|
||||
|
||||
(define (list-copy ls)
|
||||
(let lp ((ls ls) (res '()))
|
||||
(if (pair? ls)
|
||||
(lp (cdr ls) (cons (car ls) res))
|
||||
(append (reverse res) ls))))
|
||||
|
||||
(define (list-set! ls k x)
|
||||
(cond ((null? ls) (error "invalid list index"))
|
||||
((zero? k) (set-car! ls x))
|
||||
(else (list-set! (cdr ls) (- k 1) x))))
|
||||
|
||||
;;; 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))))
|
||||
|
102
srfi/list-queues/list-queues-test.scm
Normal file
102
srfi/list-queues/list-queues-test.scm
Normal file
|
@ -0,0 +1,102 @@
|
|||
(cond-expand
|
||||
(chicken (use test srfi-117))
|
||||
(chibi (import (chibi test) (list-queues)))
|
||||
)
|
||||
|
||||
(test-group "list-queues"
|
||||
|
||||
(test-group "list-queues/simple"
|
||||
(test '(1 1 1) (list-queue-list (make-list-queue '(1 1 1))))
|
||||
(define x (list-queue 1 2 3))
|
||||
(test '(1 2 3) (list-queue-list x))
|
||||
(define x1 (list 1 2 3))
|
||||
(define x2 (make-list-queue x1 (cddr x1)))
|
||||
(test 3 (list-queue-back x2))
|
||||
(define y (list-queue 4 5))
|
||||
(test-assert (list-queue? y))
|
||||
(define z (list-queue-append x y))
|
||||
(test '(1 2 3 4 5) (list-queue-list z))
|
||||
(define z2 (list-queue-append! x (list-queue-copy y)))
|
||||
(test '(1 2 3 4 5) (list-queue-list z2))
|
||||
(test 1 (list-queue-front z))
|
||||
(test 5 (list-queue-back z))
|
||||
(list-queue-remove-front! y)
|
||||
(test '(5) (list-queue-list y))
|
||||
(list-queue-remove-back! y)
|
||||
(test-assert (list-queue-empty? y))
|
||||
(test-error (list-queue-remove-front! y))
|
||||
(test-error (list-queue-remove-back! y))
|
||||
(test '(1 2 3 4 5) (list-queue-list z))
|
||||
(test '(1 2 3 4 5) (list-queue-remove-all! z2))
|
||||
(test-assert (list-queue-empty? z2))
|
||||
(list-queue-remove-all! z)
|
||||
(list-queue-add-front! z 1)
|
||||
(list-queue-add-front! z 0)
|
||||
(list-queue-add-back! z 2)
|
||||
(list-queue-add-back! z 3)
|
||||
(test '(0 1 2 3) (list-queue-list z))
|
||||
) ; end list-queues/simple
|
||||
|
||||
(test-group "list-queues/whole"
|
||||
(define a (list-queue 1 2 3))
|
||||
(define b (list-queue-copy a))
|
||||
(test '(1 2 3) (list-queue-list b))
|
||||
(list-queue-add-front! b 0)
|
||||
(test '(1 2 3) (list-queue-list a))
|
||||
(test 4 (length (list-queue-list b)))
|
||||
(define c (list-queue-concatenate (list a b)))
|
||||
(test '(1 2 3 0 1 2 3) (list-queue-list c))
|
||||
) ; end list-queues/whole
|
||||
|
||||
(test-group "list-queues/map"
|
||||
(define r (list-queue 1 2 3))
|
||||
(define s (list-queue-map (lambda (x) (* x 10)) r))
|
||||
(test '(10 20 30) (list-queue-list s))
|
||||
(list-queue-map! (lambda (x) (+ x 1)) r)
|
||||
(test '(2 3 4) (list-queue-list r))
|
||||
(define sum 0)
|
||||
(list-queue-for-each (lambda (x) (set! sum (+ sum x))) s)
|
||||
(test 60 sum)
|
||||
) ; end list-queues/map
|
||||
|
||||
(test-group "list-queues/conversion"
|
||||
(define n (list-queue 5 6))
|
||||
(list-queue-set-list! n (list 1 2))
|
||||
(test '(1 2) (list-queue-list n))
|
||||
(define d (list 1 2 3))
|
||||
(define e (cddr d))
|
||||
(define f (make-list-queue d e))
|
||||
(define-values (dx ex) (list-queue-first-last f))
|
||||
(test-assert (eq? d dx))
|
||||
(test-assert (eq? e ex))
|
||||
(test '(1 2 3) (list-queue-list f))
|
||||
(list-queue-add-front! f 0)
|
||||
(list-queue-add-back! f 4)
|
||||
(test '(0 1 2 3 4) (list-queue-list f))
|
||||
(define g (make-list-queue d e))
|
||||
(test '(1 2 3 4) (list-queue-list g))
|
||||
(define h (list-queue 5 6))
|
||||
(list-queue-set-list! h d e)
|
||||
(test '(1 2 3 4) (list-queue-list h))
|
||||
); end list-queues/conversion
|
||||
|
||||
(test-group "list-queues/unfold"
|
||||
(define (double x) (* x 2))
|
||||
(define (done? x) (> x 3))
|
||||
(define (add1 x) (+ x 1))
|
||||
(define x (list-queue-unfold done? double add1 0))
|
||||
(test '(0 2 4 6) (list-queue-list x))
|
||||
(define y (list-queue-unfold-right done? double add1 0))
|
||||
(test '(6 4 2 0) (list-queue-list y))
|
||||
(define x0 (list-queue 8))
|
||||
(define x1 (list-queue-unfold done? double add1 0 x0))
|
||||
(test '(0 2 4 6 8) (list-queue-list x1))
|
||||
(define y0 (list-queue 8))
|
||||
(define y1 (list-queue-unfold-right done? double add1 0 y0))
|
||||
(test '(8 6 4 2 0) (list-queue-list y1))
|
||||
|
||||
) ; end list-queues/unfold
|
||||
|
||||
) ; end list-queues
|
||||
|
||||
(test-exit)
|
Loading…
Add table
Reference in a new issue