212 lines
5.6 KiB
Scheme
212 lines
5.6 KiB
Scheme
;;; Random useful utilities.
|
|
;;; Copyright (c) 1993 by Olin Shivers.
|
|
|
|
(define (del elt lis)
|
|
(letrec ((del (lambda (lis)
|
|
(if (pair? lis)
|
|
(let* ((head (car lis))
|
|
(tail (cdr lis))
|
|
(new-tail (del tail)))
|
|
(if (equal? head elt) new-tail
|
|
(if (eq? tail new-tail) lis
|
|
(cons head new-tail))))
|
|
'()))))
|
|
(del lis)))
|
|
|
|
(define (delete pred lis)
|
|
(filter (lambda (x) (not (pred x))) lis))
|
|
|
|
(define (index str c . maybe-start)
|
|
(let ((start (max 0 (optional-arg maybe-start 0)))
|
|
(len (string-length str)))
|
|
(do ((i start (+ 1 i)))
|
|
((or (>= i len)
|
|
(char=? c (string-ref str i)))
|
|
(and (< i len) i)))))
|
|
|
|
(define (rindex str c . maybe-start)
|
|
(let* ((len (string-length str))
|
|
(start (min (optional-arg maybe-start len)
|
|
len)))
|
|
(do ((i (- start 1) (- i 1)))
|
|
((or (< i 0)
|
|
(char=? c (string-ref str i)))
|
|
(and (>= i 0) i)))))
|
|
|
|
;;; (f (f (f zero x1) x2) x3)
|
|
;;; [Richard's does (f x3 (f x2 (f x1 zero)))
|
|
(define (reduce f zero l)
|
|
(letrec ((lp (lambda (val rest)
|
|
(if (pair? rest) (lp (f val (car rest)) (cdr rest))
|
|
val))))
|
|
(lp zero l)))
|
|
|
|
(define (filter pred list)
|
|
(letrec ((filter (lambda (list)
|
|
(if (pair? list)
|
|
(let* ((head (car list))
|
|
(tail (cdr list))
|
|
(new-tail (filter tail)))
|
|
(if (pred head)
|
|
(if (eq? tail new-tail) list
|
|
(cons head new-tail))
|
|
new-tail))
|
|
'()))))
|
|
(filter list)))
|
|
|
|
(define (first pred list)
|
|
(letrec ((lp (lambda (list)
|
|
(and (pair? list)
|
|
(let ((head (car list)))
|
|
(if (pred head) head
|
|
(lp (cdr list))))))))
|
|
(lp list)))
|
|
|
|
(define any first)
|
|
|
|
;;; Returns the first true value produced by PRED, not the list element
|
|
;;; that satisfied PRED.
|
|
|
|
(define (first? pred list)
|
|
(letrec ((lp (lambda (list)
|
|
(and (pair? list)
|
|
(or (pred (car list))
|
|
(lp (cdr list)))))))
|
|
(lp list)))
|
|
|
|
(define any? first?)
|
|
|
|
(define (every? pred list)
|
|
(letrec ((lp (lambda (list)
|
|
(or (not (pair? list))
|
|
(and (pred (car list))
|
|
(lp (cdr list)))))))
|
|
(lp list)))
|
|
|
|
(define (mapv f v)
|
|
(let* ((len (vector-length v))
|
|
(ans (make-vector len)))
|
|
(do ((i 0 (+ i 1)))
|
|
((= i len) ans)
|
|
(vector-set! ans i (f (vector-ref v i))))))
|
|
|
|
(define (mapv! f v)
|
|
(let ((len (vector-length v)))
|
|
(do ((i 0 (+ i 1)))
|
|
((= i len) v)
|
|
(vector-set! v i (f (vector-ref v i))))))
|
|
|
|
(define (vector-every? pred v)
|
|
(let lp ((i (- (vector-length v) 1)))
|
|
(or (< i 0)
|
|
(and (pred (vector-ref v i))
|
|
(lp (- i 1))))))
|
|
|
|
(define (copy-vector v)
|
|
(let* ((len (vector-length v))
|
|
(ans (make-vector len)))
|
|
(do ((i (- len 1) (- i 1)))
|
|
((< i 0) ans)
|
|
(vector-set! ans i (vector-ref v i)))))
|
|
|
|
;;; These two utility funs are for parsing optional last arguments,
|
|
;;; e.g. the PORT arg in
|
|
;;; (write-string string [port])
|
|
;;; (define (write-string str . maybe-port) ...).
|
|
|
|
(define (optional-arg maybe-arg default)
|
|
(cond ((null? maybe-arg) default)
|
|
((null? (cdr maybe-arg)) (car maybe-arg))
|
|
(else (error "too many optional arguments" maybe-arg))))
|
|
|
|
|
|
(define (optional-arg* maybe-arg default-thunk)
|
|
(if (null? maybe-arg) (default-thunk) (car maybe-arg)))
|
|
|
|
;;; (PARSE-OPTIONALS arg-list . default-list)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; This function generalises OPTIONAL-ARG to the multi-argument
|
|
;;; case. ARG-LIST is a list of rest args passed to a procedure.
|
|
;;; DEFAULT-LIST are the default values for the procedure.
|
|
;;; We compute a list of values, with the elts of ARG-LIST overriding
|
|
;;; the defaults. It is an error if there are more args than defaults.
|
|
;;; The values are returned as multiple values, suitable for binding
|
|
;;; with RECEIVE.
|
|
;;;
|
|
;;; Example:
|
|
;;; (define (read-string! str . maybe-args)
|
|
;;; (receive (port start end)
|
|
;;; (parse-optionals maybe-args
|
|
;;; (current-input-port) 0 (string-length str))
|
|
;;; ...))
|
|
|
|
(define (parse-optionals arg-list . default-list)
|
|
(let lp ((arglist arg-list)
|
|
(defaults default-list)
|
|
(vals '()))
|
|
(if (pair? defaults)
|
|
(if (pair? arglist)
|
|
|
|
;; The supplied arg overrides the default.
|
|
(lp (cdr arglist)
|
|
(cdr defaults)
|
|
(cons (car arglist) vals))
|
|
|
|
;; No more args. Use up all the remaining defaults & return.
|
|
(apply values (reverse (append (reverse defaults) vals))))
|
|
|
|
;; No more defaults. Better not be any more args.
|
|
(if (null? arglist)
|
|
(apply values (reverse vals))
|
|
(error "Too many optional arguments" arg-list)))))
|
|
|
|
(define (check-arg pred val caller)
|
|
(if (pred val) val
|
|
(check-arg pred (error "Bad argument" val pred caller) caller)))
|
|
|
|
(define (conjoin f g)
|
|
(lambda args (and (apply f args) (apply g args))))
|
|
|
|
(define (disjoin f g)
|
|
(lambda args (or (apply f args) (apply g args))))
|
|
|
|
(define (negate f) (lambda args (not (apply f args))))
|
|
|
|
(define (compose f g)
|
|
(lambda args (call-with-values (lambda () (apply g args)) f)))
|
|
|
|
|
|
(define (reverse! lis)
|
|
(let lp ((lis lis) (prev '()))
|
|
(if (not (pair? lis)) prev
|
|
(let ((tail (cdr lis)))
|
|
(set-cdr! lis prev)
|
|
(lp tail lis)))))
|
|
|
|
(define call/cc call-with-current-continuation)
|
|
|
|
(define (deposit-bit-field bits mask field)
|
|
(bitwise-ior (bitwise-and field mask)
|
|
(bitwise-and bits (bitwise-not mask))))
|
|
|
|
|
|
(define (nth lis i)
|
|
(if (< i 0) (error "nth: illegal list index" i)
|
|
(let lp ((l lis) (i i))
|
|
(if (pair? l)
|
|
(if (zero? i) (car l)
|
|
(lp (cdr l) (- i 1)))
|
|
(error "nth: index too large" lis i)))))
|
|
|
|
|
|
(define (deprecated-proc proc name . maybe-preferred-msg)
|
|
(let ((warned? #f))
|
|
(lambda args
|
|
(cond ((not warned?)
|
|
(set! warned? #t)
|
|
(apply warn
|
|
"Deprecated procedure (may not be supported in a future release)"
|
|
name
|
|
maybe-preferred-msg)))
|
|
(apply proc args))))
|