📄 srfi1.scm
字号:
(values l lis)) ; Done. (else (lp l (cdr l)))))))))|#;;; Inline us, please.(define (remove pred l) (filter (lambda (x) (not (pred x))) l))(define (remove! pred l) (filter! (lambda (x) (not (pred x))) l));;; Here's the taxonomy for the DELETE/ASSOC/MEMBER functions.;;; (I don't actually think these are the world's most important;;; functions -- the procedural FILTER/REMOVE/FIND/FIND-TAIL variants;;; are far more general.);;;;;; Function Action;;; ---------------------------------------------------------------------------;;; remove pred lis Delete by general predicate;;; delete x lis [=] Delete by element comparison;;; ;;; find pred lis Search by general predicate;;; find-tail pred lis Search by general predicate;;; member x lis [=] Search by element comparison;;;;;; assoc key lis [=] Search alist by key comparison;;; alist-delete key alist [=] Alist-delete by key comparison(define (delete x lis #!optional (maybe-= equal?)) (filter (lambda (y) (not (maybe-= x y))) lis))(define (delete! x lis #!optional (maybe-= equal?)) (filter! (lambda (y) (not (maybe-= x y))) lis));;; Extended from R4RS to take an optional comparison argument.; In kawa.lib.lists.;(define (member x lis #!optional (maybe-= equal?)); (find-tail (lambda (y) (maybe-= x y)) lis));;; R4RS, hence we don't bother to define.;;; The MEMBER and then FIND-TAIL call should definitely;;; be inlined for MEMQ & MEMV.;(define (memq x lis) (member x lis eq?));(define (memv x lis) (member x lis eqv?));;; right-duplicate deletion;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; delete-duplicates delete-duplicates!;;;;;; Beware -- these are N^2 algorithms. To efficiently remove duplicates;;; in long lists, sort the list to bring duplicates together, then use a ;;; linear-time algorithm to kill the dups. Or use an algorithm based on;;; element-marking. The former gives you O(n lg n), the latter is linear.(define (delete-duplicates lis #!optional (maybe-= :: <procedure> equal?)) (let recur ((lis lis)) (if (null-list? lis) lis (let* ((x (car lis)) (tail (cdr lis)) (new-tail (recur (delete x tail maybe-=)))) (if (eq? tail new-tail) lis (cons x new-tail))))))(define (delete-duplicates! lis #!optional (maybe-= :: <procedure> equal?)) (let recur ((lis lis)) (if (null-list? lis) lis (let* ((x (car lis)) (tail (cdr lis)) (new-tail (recur (delete! x tail maybe-=)))) (if (eq? tail new-tail) lis (cons x new-tail))))));;; alist stuff;;;;;;;;;;;;;;;;;; Extended from R4RS to take an optional comparison argument.;; In kawa.lib.lists.;;(define (assoc x lis #!optional (maybe-= equal?));; (find (lambda (entry) (maybe-= x (car entry))) lis))(define (alist-cons key datum alist) (cons (cons key datum) alist))(define (alist-copy alist) (map (lambda (elt) (cons (car elt) (cdr elt))) alist))(define (alist-delete key alist #!optional (maybe-= equal?)) (filter (lambda (elt) (not (maybe-= key (car elt)))) alist))(define (alist-delete! key alist #!optional (maybe-= equal?)) (filter! (lambda (elt) (not (maybe-= key (car elt)))) alist));;; find find-tail take-while drop-while span break any every list-index;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;(define (find pred list) (cond ((find-tail pred list) => car) (else #f)))(define (find-tail pred :: <procedure> list) (let lp ((list list)) (and (not (null-list? list)) (if (pred (car list)) list (lp (cdr list))))))(define (take-while pred :: <procedure> lis) (let recur ((lis lis)) (if (null-list? lis) '() (let ((x (car lis))) (if (pred x) (cons x (recur (cdr lis))) '())))))(define (drop-while pred :: <procedure> lis) (let lp ((lis lis)) (if (null-list? lis) '() (if (pred (car lis)) (lp (cdr lis)) lis))))(define (take-while! pred :: <procedure> lis) (if (or (null-list? lis) (not (pred (car lis)))) '() (begin (let lp ((prev lis) (rest (cdr lis))) (if (pair? rest) (let ((x (car rest))) (if (pred x) (lp rest (cdr rest)) (set-cdr! prev '()))))) lis)))(define (span pred :: <procedure> lis) (let loop ((lis lis) (res '())) (if (null-list? lis) (values (reverse! res) lis) (let ((head (car lis))) (if (pred head) (loop (cdr lis) (cons head res)) (values (reverse! res) lis))))))(define (span! pred :: <procedure> lis) (if (or (null-list? lis) (not (pred (car lis)))) (values '() lis) (let ((suffix (let lp ((prev lis) (rest (cdr lis))) (if (null-list? rest) rest (let ((x (car rest))) (if (pred x) (lp rest (cdr rest)) (begin (set-cdr! prev '()) rest))))))) (values lis suffix)))) (define (break pred lis) (span (lambda (x) (not (pred x))) lis))(define (break! pred lis) (span! (lambda (x) (not (pred x))) lis))(define (any pred :: <procedure> lis1 . lists) (if (pair? lists) ;; N-ary case (receive (heads tails) (%cars+cdrs (cons lis1 lists)) (and (pair? heads) (let lp ((heads heads) (tails tails)) (let* ((split (%cars+cdrs/pair tails)) (next-heads (car split)) (next-tails (cdr split))) (if (pair? next-heads) (or (apply pred heads) (lp next-heads next-tails)) (apply pred heads)))))) ; Last PRED app is tail call. ;; Fast path (and (not (null-list? lis1)) (let lp ((head (car lis1)) (tail (cdr lis1))) (if (null-list? tail) (pred head) ; Last PRED app is tail call. (or (pred head) (lp (car tail) (cdr tail))))))));(define (every pred list) ; Simple definition.; (let lp ((list list)) ; Doesn't return the last PRED value.; (or (not (pair? list)); (and (pred (car list)); (lp (cdr list))))))(define (every pred :: <procedure> lis1 . lists) (if (pair? lists) ;; N-ary case (receive (heads tails) (%cars+cdrs (cons lis1 lists)) (or (not (pair? heads)) (let lp ((heads heads) (tails tails)) (receive (next-heads next-tails) (%cars+cdrs tails) (if (pair? next-heads) (and (apply pred heads) (lp next-heads next-tails)) (apply pred heads)))))) ; Last PRED app is tail call. ;; Fast path (or (null-list? lis1) (let lp ((head (car lis1)) (tail (cdr lis1))) (if (null-list? tail) (pred head) ; Last PRED app is tail call. (and (pred head) (lp (car tail) (cdr tail))))))))(define-syntax %every (syntax-rules () ((%every pred lis1) (let lp ((head (car lis1)) (tail (cdr lis1))) (and (null-list? tail) (pred head) (lp (car tail) (cdr tail)))))))(define (list-index pred :: <procedure> lis1 . lists) (if (pair? lists) ;; N-ary case (let lp ((lists (cons lis1 lists)) (n 0)) (receive (heads tails) (%cars+cdrs lists) (and (pair? heads) (if (apply pred heads) n (lp tails (+ n 1)))))) ;; Fast path (let lp ((lis lis1) (n 0)) (and (not (null-list? lis)) (if (pred (car lis)) n (lp (cdr lis) (+ n 1)))))));;; Reverse;;;;;;;;;;;;R4RS, so not defined here.;(define (reverse lis) (fold cons '() lis)) ;(define (reverse! lis); (pair-fold (lambda (pair tail) (set-cdr! pair tail) pair) '() lis));(define (reverse! lis) ;; Kawa primitive; (let lp ((lis lis) (ans '())); (if (null-list? lis) ans; (let ((tail (cdr lis))); (set-cdr! lis ans); (lp tail lis)))));;; Lists-as-sets;;;;;;;;;;;;;;;;;;;; This is carefully tuned code; do not modify casually.;;; - It is careful to share storage when possible;;;; - Side-effecting code tries not to perform redundant writes.;;; - It tries to avoid linear-time scans in special cases where constant-time;;; computations can be performed.;;; - It relies on similar properties from the other list-lib procs it calls.;;; For example, it uses the fact that the implementations of MEMBER and;;; FILTER in this source code share longest common tails between args;;; and results to get structure sharing in the lset procedures.(define-private (%lset2<= = lis1 lis2) (every (lambda (x) (member x lis2 =)) lis1))(define (lset<= = :: <procedure> . lists) (or (not (pair? lists)) ; 0-ary case (let lp ((s1 (car lists)) (rest (cdr lists))) (or (not (pair? rest)) (let ((s2 (car rest)) (rest (cdr rest))) (and (or (eq? s2 s1) ; Fast path (%lset2<= = s1 s2)) ; Real test (lp s2 rest)))))))(define (lset= = :: <procedure> . lists) (or (not (pair? lists)) ; 0-ary case (let lp ((s1 (car lists)) (rest (cdr lists))) (or (not (pair? rest)) (let ((s2 (car rest)) (rest (cdr rest))) (and (or (eq? s1 s2) ; Fast path (and (%lset2<= = s1 s2) (%lset2<= = s2 s1))) ; Real test (lp s2 rest)))))))(define (lset-adjoin = :: <procedure> lis . elts) (fold (lambda (elt ans) (if (member elt ans =) ans (cons elt ans))) lis elts))(define (lset-union = :: <procedure> . lists) (reduce (lambda (lis ans) ; Compute ANS + LIS. (cond ((null? lis) ans) ; Don't copy any lists ((null? ans) lis) ; if we don't have to. ((eq? lis ans) ans) (else (fold (lambda (elt ans) (if (any (lambda (x) (= x elt)) ans) ans (cons elt ans))) ans lis)))) '() lists))(define (lset-union! = :: <procedure> . lists) (reduce (lambda (lis ans) ; Splice new elts of LIS onto the front of ANS. (cond ((null? lis) ans) ; Don't copy any lists ((null? ans) lis) ; if we don't have to. ((eq? lis ans) ans) (else (pair-fold (lambda (pair ans) (let ((elt (car pair))) (if (any (lambda (x) (= x elt)) ans) ans (begin (set-cdr! pair ans) pair)))) ans lis)))) '() lists))(define (lset-intersection = :: <procedure> lis1 . lists) (let ((lists (delete lis1 lists eq?))) ; Throw out any LIS1 vals. (cond ((any null-list? lists) '()) ; Short cut ((null? lists) lis1) ; Short cut (else (filter (lambda (x) (every (lambda (lis) (member x lis =)) lists)) lis1)))))(define (lset-intersection! = :: <procedure> lis1 . lists) (let ((lists (delete lis1 lists eq?))) ; Throw out any LIS1 vals. (cond ((any null-list? lists) '()) ; Short cut ((null? lists) lis1) ; Short cut (else (filter! (lambda (x) (every (lambda (lis) (member x lis =)) lists)) lis1)))))(define (lset-difference = :: <procedure> lis1 . lists) (let ((lists (filter pair? lists))) ; Throw out empty lists. (cond ((null? lists) lis1) ; Short cut ((memq lis1 lists) '()) ; Short cut (else (filter (lambda (x) (every (lambda (lis) (not (member x lis =))) lists)) lis1)))))(define (lset-difference! = :: <procedure> lis1 . lists) (let ((lists (filter pair? lists))) ; Throw out empty lists. (cond ((null? lists) lis1) ; Short cut ((memq lis1 lists) '()) ; Short cut (else (filter! (lambda (x) (every (lambda (lis) (not (member x lis =))) lists)) lis1)))))(define (lset-xor = :: <procedure> . lists) (reduce (lambda (b a) ; Compute A xor B: ;; Note that this code relies on the constant-time ;; short-cuts provided by LSET-DIFF+INTERSECTION, ;; LSET-DIFFERENCE & APPEND to provide constant-time short ;; cuts for the cases A = (), B = (), and A eq? B. It takes ;; a careful case analysis to see it, but it's carefully ;; built in. ;; Compute a-b and a^b, then compute b-(a^b) and ;; cons it onto the front of a-b. (receive (a-b a-int-b) (lset-diff+intersection = a b) (cond ((null? a-b) (lset-difference = b a)) ((null? a-int-b) (append b a)) (else (fold (lambda (xb ans) (if (member xb a-int-b =) ans (cons xb ans))) a-b b))))) '() lists))(define (lset-xor! = :: <procedure> . lists) (reduce (lambda (b a) ; Compute A xor B: ;; Note that this code relies on the constant-time ;; short-cuts provided by LSET-DIFF+INTERSECTION, ;; LSET-DIFFERENCE & APPEND to provide constant-time short ;; cuts for the cases A = (), B = (), and A eq? B. It takes ;; a careful case analysis to see it, but it's carefully ;; built in. ;; Compute a-b and a^b, then compute b-(a^b) and ;; cons it onto the front of a-b. (receive (a-b a-int-b) (lset-diff+intersection! = a b) (cond ((null? a-b) (lset-difference! = b a)) ((null? a-int-b) (append! b a)) (else (pair-fold (lambda (b-pair ans) (if (member (car b-pair) a-int-b =) ans (begin (set-cdr! b-pair ans) b-pair))) a-b b))))) '() lists))(define (lset-diff+intersection = :: <procedure> lis1 . lists) (cond ((every null-list? lists) (values lis1 '())) ; Short cut ((memq lis1 lists) (values '() lis1)) ; Short cut (else (partition (lambda (elt) (not (any (lambda (lis) (member elt lis =)) lists))) lis1))))(define (lset-diff+intersection! = :: <procedure> lis1 . lists) (cond ((every null-list? lists) (values lis1 '())) ; Short cut ((memq lis1 lists) (values '() lis1)) ; Short cut (else (partition! (lambda (elt) (not (any (lambda (lis) (member elt lis =)) lists))) lis1))))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -