racket/list: adjust `add-between' keyword handling
Add a `#:nothing' argument so the no-value value can be made explicit --- based on discussion with Eli, but pending further review. Also, renamed `#:first' to `#:before-first' and `#:last' to `#:after-last' to be more clear, more parallel ro `#:before-last', and avoid a collision with prominent function names.
This commit is contained in:
parent
eb4e040981
commit
a6e263741a
|
@ -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])
|
||||
|
|
|
@ -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])]{
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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?,
|
||||
|
|
Loading…
Reference in New Issue
Block a user