scsh-0.5/scsh/utilities.scm

218 lines
5.7 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))))
(define (real->exact-integer x)
(let ((f (round x)))
(if (inexact? f) (inexact->exact f) f)))