fix `slicef-after`

dev-refac-2020
Matthew Butterick 5 years ago
parent 73e4b8b0ff
commit 297a93767b

@ -35,27 +35,28 @@
((list? procedure?) (boolean?) . ->* . (listof list?))
(unless (list? xs)
(raise-argument-error 'slicef-at "list?" xs))
(unless (procedure? pred)
(raise-argument-error 'slicef-at "procedure?" pred))
(let loop ([xs xs][acc empty])
(match xs
[(== empty) (reverse acc)]
[(cons (? pred first) rest)
(define-values (not-pred-xs tail) (splitf-at rest (negate pred)))
(loop tail (cons (cons first not-pred-xs) acc))]
[rest
(define-values (not-pred-xs tail) (splitf-at rest (negate pred)))
[(list* (? pred pred-x) (? (negate pred) not-pred-xs) ... tail)
(loop tail (cons (cons pred-x not-pred-xs) acc))]
[(list* (? (negate pred) not-pred-xs) ... tail)
(loop tail (if force? acc (cons not-pred-xs acc)))])))
(define+provide+safe (slicef-after xs pred)
(list? procedure? . -> . (listof list?))
(define+provide+safe (slicef-after xs pred [force? #f])
((list? procedure?) (boolean?) . ->* . (listof list?))
(unless (list? xs)
(raise-argument-error 'slicef-after "list?" xs))
(unless (procedure? pred)
(raise-argument-error 'slicef-after "procedure?" pred))
(let loop ([xs xs][acc empty])
(if (empty? xs)
(reverse acc)
(match/values (splitf-at xs (negate pred))
[(not-pred-xs (cons first-pred-x other-pred-xs))
(loop other-pred-xs (cons (append not-pred-xs (list first-pred-x)) acc))]
[(not-pred-xs _) not-pred-xs]))))
(match xs
[(== empty) (reverse acc)]
[(list* (? (negate pred) not-pred-xs) ... (? pred pred-x) tail)
(loop tail (cons (append not-pred-xs (list pred-x)) acc))]
[tail (loop empty (if force? acc (cons tail acc)))])))
(define+provide+safe (slice-at xs len [force? #f])
((list? exact-nonnegative-integer?) (boolean?) . ->* . (listof list?))

@ -74,7 +74,9 @@ Divide @racket[_lst] into sublists that are homogeneously @racket[_pred] or not
[pred procedure?]
[force? boolean? #f])
(listof list?)]
Divide @racket[_lst] into sublists starting with elements matching @racket[_pred]. The first element of the first sublist may not match @racket[_pred]. Or, if you really & truly want only the sublists starting with an element matching @racket[_pred], set @racket[_force?] to @racket[#t].
Divide @racket[_lst] into sublists, each starting with an element matching @racket[_pred]. The first element of the first sublist may not match @racket[_pred]. But if you really & truly want only the sublists starting with an element matching @racket[_pred], set @racket[_force?] to @racket[#true].
If none of the elements match @racket[_pred], there is no slice to be made, and the result is the whole input list.
@examples[#:eval my-eval
(slicef-at (range 5) even?)
@ -86,9 +88,12 @@ Divide @racket[_lst] into sublists starting with elements matching @racket[_pred
@defproc[
(slicef-after
[lst list?]
[pred procedure?])
[pred procedure?]
[force? boolean? #f]))
(listof list?)]
Divide @racket[_lst] into sublists ending with elements matching @racket[_pred]. (Distinct from @racket[slicef-at], which gives you sublists that @italic{start} with elements matching @racket[_pred].) If none of the elements match @racket[_pred], there is no slice to be made, and the result is the whole input list.
Divide @racket[_lst] into sublists, each ending with an element matching @racket[_pred]. The last element of the last sublist may not match @racket[_pred]. But if you really & truly want only the sublists ending with an element matching @racket[_pred], set @racket[_force?] to @racket[#true].
If none of the elements match @racket[_pred], there is no slice to be made, and the result is the whole input list.
@examples[#:eval my-eval
(slicef-after '(1 2 2 1 2) even?)

@ -198,6 +198,14 @@
(check-equal? (slicef-at '(1 2 2 1 2) even?) '((1) (2) (2 1) (2)))
(check-equal? (slicef-at '(1 2 2 1 2) even? #t) '((2) (2 1) (2)))
(check-equal? (slicef-after (range 5) even?) '((0) (1 2) (3 4)))
(check-equal? (slicef-after (range 5) odd?) '((0 1) (2 3) (4)))
(check-equal? (slicef-after (range 5) odd? #t) '((0 1) (2 3)))
(check-equal? (slicef-after (range 5) procedure?) '((0 1 2 3 4)))
(check-equal? (slicef-after '(2 1 2 2 1) even?) '((2) (1 2) (2) (1)))
(check-equal? (slicef-after '(2 1 2 2 1) even? #t) '((2) (1 2) (2)))
(check-equal? (sublist (range 5) 0 0) '())
(check-equal? (sublist (range 5) 0 1) '(0))

Loading…
Cancel
Save