1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
; Copyright (c) 1993-2001 by Richard Kelsey and Jonathan Rees. See file COPYING.
; This is file util.scm.
;;;; Utilities
(define (unspecific) (if #f #f))
(define (reduce cons nil list) ;used by length, append, etc.
(if (null? list)
nil
(cons (car list) (reduce cons nil (cdr list)))))
(define (filter pred lst)
(reduce (lambda (x rest)
(if (pred x) (cons x rest) rest))
'()
lst))
; Position of an object within a list
(define (pos pred)
(lambda (thing l)
(let loop ((i 0) (l l))
(cond ((null? l) #f)
((pred thing (car l)) i)
(else (loop (+ i 1) (cdr l)))))))
(define posq (pos eq?))
(define posv (pos eqv?))
(define position (pos equal?))
; Is pred true of any element of l?
(define (any pred l)
;; (reduce or #f l), sort of
(if (null? l)
#f
(or (pred (car l))
(any pred (cdr l)))))
; Is pred true of every element of l?
(define (every pred l)
;; (reduce and #t l), sort of
(if (null? l)
#t
(and (pred (car l)) (every pred (cdr l)))))
(define (sublist l start end)
(if (> start 0)
(sublist (cdr l) (- start 1) (- end 1))
(let recur ((l l) (end end))
(if (= end 0)
'()
(cons (car l) (recur (cdr l) (- end 1)))))))
(define (last x)
(if (null? (cdr x))
(car x)
(last (cdr x))))
(define (insert x l <)
(cond ((null? l) (list x))
((< x (car l)) (cons x l))
(else (cons (car l) (insert x (cdr l) <)))))
;----------------
; Variations on a theme.
;
; FOLD is a tail-recursive version of REDUCE.
(define (fold folder list accumulator)
(do ((list list (cdr list))
(accum accumulator (folder (car list) accum)))
((null? list)
accum)))
(define (fold->2 folder list acc0 acc1)
(let loop ((list list) (acc0 acc0) (acc1 acc1))
(if (null? list)
(values acc0 acc1)
(call-with-values
(lambda ()
(folder (car list) acc0 acc1))
(lambda (acc0 acc1)
(loop (cdr list) acc0 acc1))))))
(define (fold->3 folder list acc0 acc1 acc2)
(let loop ((list list) (acc0 acc0) (acc1 acc1) (acc2 acc2))
(if (null? list)
(values acc0 acc1 acc2)
(call-with-values
(lambda ()
(folder (car list) acc0 acc1 acc2))
(lambda (acc0 acc1 acc2)
(loop (cdr list) acc0 acc1 acc2))))))
;----------------
; A version of LET and LET* which allows clauses that return multiple values.
;
; There is another copy of this in big/mvlet.scm.
;
; MV = multiple-value
;
; (mvlet (<clause> ...) <body>)
; (mvlet* (<clause> ...) <body>)
;
; <clause> ::= (<ids> <expression>)
; <ids> ::= <id> | (<id> ...) | (<id> ... . <id>)
;
; A clause of the form (<id> <exp>) is like a normal LET clause. There is no
; clause equivalent to
; (call-with-values (lambda () <expression>)
; (lambda <id> <body>))
(define-syntax mvlet
(syntax-rules ()
((mvlet () body ...)
(let () body ...))
((mvlet (clause ...) body ...)
(mvlet-helper (clause ...) () (body ...)))))
(define-syntax mvlet-helper
(syntax-rules ()
((mvlet-helper () clauses (body ...))
(let clauses body ...))
((mvlet-helper (((var . more-vars) val) more ...) clauses body)
(copy-vars (var . more-vars) () val (more ...) clauses body))
((mvlet-helper ((var val) more ...) clauses body)
(mvlet-helper (more ...) ((var val) . clauses) body))))
(define-syntax copy-vars
(syntax-rules ()
((copy-vars (var . more-vars) (copies ...)
val more clauses body)
(copy-vars more-vars (copies ... x)
val more ((var x) . clauses) body))
((copy-vars () copies val more clauses body)
(call-with-values
(lambda () val)
(lambda copies
(mvlet-helper more clauses body))))
((copy-vars last (copies ...) val more clauses body)
(call-with-values
(lambda () val)
(lambda (copies ... . lastx)
(mvlet-helper more ((last lastx) . clauses) body))))))
(define-syntax mvlet*
(syntax-rules ()
((mvlet* () body ...)
(let () body ...))
((mvlet* (((vars ...) val) clause ...) body ...)
(call-with-values
(lambda () val)
(lambda (vars ...)
(mvlet (clause ...) body ...))))
((mvlet* ((var val) clause ...) body ...)
(let ((var val)) (mvlet (clause ...) body ...)))))
|