diff --git a/collects/racket/list.rkt b/collects/racket/list.rkt index 35d42a5680..eef34514b5 100644 --- a/collects/racket/list.rkt +++ b/collects/racket/list.rkt @@ -177,26 +177,37 @@ ;; General note: many non-tail recursive, which are just as fast in racket -(define none (gensym 'none)) -(define (add-between l x #:splice? [splice? #f] - #:first [first none] #:last [last none] - #:before-last [before-last none]) +(define default-nothing (gensym 'nothing)) +(define (add-between l x + #:splice? [splice? #f] + #:nothing [nothing default-nothing] + #:before-first [before-first nothing] + #:before-last [before-last x] + #:after-last [after-last nothing]) (unless (list? l) (raise-argument-error 'add-between "list?" 0 l x)) (when splice? - (unless (list? x) - (raise-argument-error 'add-between "list?" 1 l x))) + (define (check-list x which) + (unless (list? x) + (raise-arguments-error 'add-between + (string-append "list needed in splicing mode" which) + "given" x + "given list..." l))) + (check-list x "") + (unless (eq? nothing before-first) (check-list before-first " for #:before-first")) + (check-list before-last " for #:before-last") + (unless (eq? nothing after-last) (check-list after-last " for #:after-last"))) (if (or (null? l) (null? (cdr l))) - (let* ([r (cond [(eq? last none) '()] [splice? last] [else (list last)])] + (let* ([r (cond [(eq? after-last nothing) '()] [splice? after-last] [else (list after-last)])] [r (cond [(null? l) r] [(null? r) l] [(cons (car l) r)])] - [r (cond [(eq? first none) r] - [splice? (append first r)] - [else (cons first r)])]) + [r (cond [(eq? before-first nothing) r] + [splice? (append before-first r)] + [else (cons before-first r)])]) r) (let* ([r ; main loop (two loops for efficiency, maybe not needed) (if splice? (let ([x (reverse x)] - [bl (and (not (eq? before-last none)) + [bl (and (not (eq? before-last x)) (reverse before-last))]) (let loop ([i (cadr l)] [l (cddr l)] [r '()]) (cond [(pair? l) (loop (car l) (cdr l) (cons i (append x r)))] @@ -204,20 +215,19 @@ [else (cons i (append x r))]))) (let loop ([i (cadr l)] [l (cddr l)] [r '()]) (cond [(pair? l) (loop (car l) (cdr l) (cons i (cons x r)))] - [(eq? before-last none) (cons i (cons x r))] [else (cons i (cons before-last r))])))] - ;; add `last' - [r (cond [(eq? last none) r] - [splice? (append (reverse last) r)] - [else (cons last r)])] + ;; add `after-last' + [r (cond [(eq? after-last nothing) r] + [splice? (append (reverse after-last) r)] + [else (cons after-last r)])] ;; reverse [r (reverse r)] ;; add first item [r (cons (car l) r)] - ;; add `first' - [r (cond [(eq? first none) r] - [splice? (append first r)] - [else (cons first r)])]) + ;; add `before-first' + [r (cond [(eq? before-first nothing) r] + [splice? (append before-first r)] + [else (cons before-first r)])]) r))) (define (remove-duplicates l [=? equal?] #:key [key #f]) diff --git a/collects/scribblings/reference/pairs.scrbl b/collects/scribblings/reference/pairs.scrbl index 324d3ebf25..447e874aee 100644 --- a/collects/scribblings/reference/pairs.scrbl +++ b/collects/scribblings/reference/pairs.scrbl @@ -860,39 +860,45 @@ except that it can be faster. (split-at-right '(1 2 3 4 5 6) 4) ]} + @defproc[(add-between [lst list?] [v any/c] - [#:before-last before-last any/c v] - [#:first first any/c ....] - [#:last last any/c ....] + [#:nothing nothing any/c (gensym)] + [#:before-first before-first any/c nothing] + [#:before-last before-last any/c v] + [#:after-last after-last any/c nothing] [#:splice? splice? any/c #f]) list?]{ Returns a list with the same elements as @racket[lst], but with -@racket[v] between each pair of items in @racket[lst]. The last pair of -items will have @racket[before-last] between them, which defaults to -@racket[v]. Giving a value for @racket[first] (or @racket[last]) -will make the result have that value added to its beginning (or end). +@racket[v] between each pair of elements in @racket[lst]; the last +pair of elements will have @racket[before-last] between them, instead +of @racket[v] (but @racket[before-last] defaults to @racket[v]). In +addition, if @racket[before-first] is supplied as a value other than +@racket[nothing], then @racket[before-first] is inserted before the first +element; if @racket[after-last] is supplied as a value other than +@racket[nothing], then @racket[after-last] is inserted after the last +element. + +If @racket[splice?] is true, then @racket[v], @racket[before-first], +@racket[before-last], and @racket[after-last] should be lists, and +the list elements are spliced into the result. @mz-examples[#:eval list-eval (add-between '(x y z) 'and) (add-between '(x) 'and) (add-between '("a" "b" "c" "d") "," #:before-last "and") - (add-between #:first "Todo:" + (add-between #:before-first "Todo:" '("a" "b" "c") "," #:before-last "and" - #:last ".") -] - -If @racket[splice?] is true, then @racket[v], @racket[before-last], -@racket[first], and @racket[last] should be lists, and their values are -spliced into the result. - -@mz-examples[#:eval list-eval + #:after-last ".") (add-between '(x y z) '(-) #:before-last '(- -) - #:first '(begin) #:last '(end LF) + #:before-first '(begin) #:after-last '(end LF) #:splice? #t) -] + (add-between '("a" "b" "c" "d") "," + #:nothing #f #:before-first #f #:after-last "!") + (add-between '("a" "b" "c" "d") "," + #:before-first #f #:after-last "!") +]} -} @defproc*[([(append* [lst list?] ... [lsts (listof list?)]) list?] [(append* [lst list?] ... [lsts list?]) any/c])]{ diff --git a/collects/tests/racket/list.rktl b/collects/tests/racket/list.rktl index 9d0c1d9a68..8c14a3979b 100644 --- a/collects/tests/racket/list.rktl +++ b/collects/tests/racket/list.rktl @@ -245,17 +245,19 @@ [r3 (in-list '(() (x) (x (5) y) (x (5) y (5) z) (x (5) y (5) z (5) w)))]) (test r1 add-between l 5) - (test `(0 ,@r1) add-between l 5 #:first 0) - (test `(,@r1 9) add-between l 5 #:last 9) - (test `(0 ,@r1 9) add-between l 5 #:first 0 #:last 9) + (test `(0 ,@r1) add-between l 5 #:before-first 0) + (test `(,@r1 9) add-between l 5 #:after-last 9) + (test `(0 ,@r1 9) add-between l 5 #:before-first 0 #:after-last 9) (test r2 add-between l 5 #:before-last 7) - (test `(0 ,@r2) add-between l 5 #:first 0 #:before-last 7) - (test `(,@r2 9) add-between l 5 #:last 9 #:before-last 7) - (test `(0 ,@r2 9) add-between l 5 #:first 0 #:last 9 #:before-last 7) + (test `(0 ,@r2) add-between l 5 #:before-first 0 #:before-last 7) + (test `(,@r2 9) add-between l 5 #:after-last 9 #:before-last 7) + (test `(0 ,@r2 9) add-between l 5 #:before-first 0 #:after-last 9 #:before-last 7) (test r3 add-between l '(5)) - (test `(0 ,@r3) add-between l '(5) #:first 0) - (test `(,@r3 9) add-between l '(5) #:last 9) - (test `(0 ,@r3 9) add-between l '(5) #:first 0 #:last 9)) + (test `(0 ,@r3) add-between l '(5) #:before-first 0) + (test `(,@r3 9) add-between l '(5) #:after-last 9) + (test `(0 ,@r3 9) add-between l '(5) #:before-first 0 #:after-last 9) + (test r1 add-between l 5 #:nothing #f #:before-first #f) + (test r1 add-between l 5 #:nothing #f #:after-last #f)) ;; spliced cases (for* ([x (in-list '(() (4) (4 5)))] [y (in-list '(() (6) (6 7)))]) @@ -268,20 +270,20 @@ (test r2 add-between l x #:splice? #t #:before-last y) (for ([fst (in-list '(() (0) (0 1)))]) (test `(,@fst ,@r1) add-between l x - #:splice? #t #:first fst) + #:splice? #t #:before-first fst) (test `(,@fst ,@r2) add-between l x - #:splice? #t #:first fst #:before-last y)) + #:splice? #t #:before-first fst #:before-last y)) (for ([lst (in-list '(() (9) (8 9)))]) (test `(,@r1 ,@lst) add-between l x - #:splice? #t #:last lst) + #:splice? #t #:after-last lst) (test `(,@r2 ,@lst) add-between l x - #:splice? #t #:last lst #:before-last y)) + #:splice? #t #:after-last lst #:before-last y)) (for* ([fst (in-list '(() (0) (0 1)))] [lst (in-list '(() (9) (8 9)))]) (test `(,@fst ,@r1 ,@lst) add-between l x - #:splice? #t #:first fst #:last lst) + #:splice? #t #:before-first fst #:after-last lst) (test `(,@fst ,@r2 ,@lst) add-between l x - #:splice? #t #:first fst #:last lst #:before-last y))))) + #:splice? #t #:before-first fst #:after-last lst #:before-last y))))) ;; ---------- remove-duplicates ---------- (let () diff --git a/doc/release-notes/racket/HISTORY.txt b/doc/release-notes/racket/HISTORY.txt index b745fa8808..7c0871e574 100644 --- a/doc/release-notes/racket/HISTORY.txt +++ b/doc/release-notes/racket/HISTORY.txt @@ -10,6 +10,8 @@ racket/future: handling of internal stack overflow without racket/base: guarantee portable results for current-seconds and file-or-directory-modify-seconds compiler/zo-structs: added a context field to all-from-module +racket/list: added optional arguments to add-between, including + #:splice?, #:before-first, #:before-last, and #:after-last Version 5.3.0.10 racket/base: add progress-evt?, thread-cell-values?, prefab-key?,