fix `slicef-after`

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

@ -35,27 +35,28 @@
((list? procedure?) (boolean?) . ->* . (listof list?)) ((list? procedure?) (boolean?) . ->* . (listof list?))
(unless (list? xs) (unless (list? xs)
(raise-argument-error 'slicef-at "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]) (let loop ([xs xs][acc empty])
(match xs (match xs
[(== empty) (reverse acc)] [(== empty) (reverse acc)]
[(cons (? pred first) rest) [(list* (? pred pred-x) (? (negate pred) not-pred-xs) ... tail)
(define-values (not-pred-xs tail) (splitf-at rest (negate pred))) (loop tail (cons (cons pred-x not-pred-xs) acc))]
(loop tail (cons (cons first not-pred-xs) acc))] [(list* (? (negate pred) not-pred-xs) ... tail)
[rest
(define-values (not-pred-xs tail) (splitf-at rest (negate pred)))
(loop tail (if force? acc (cons not-pred-xs acc)))]))) (loop tail (if force? acc (cons not-pred-xs acc)))])))
(define+provide+safe (slicef-after xs pred) (define+provide+safe (slicef-after xs pred [force? #f])
(list? procedure? . -> . (listof list?)) ((list? procedure?) (boolean?) . ->* . (listof list?))
(unless (list? xs) (unless (list? xs)
(raise-argument-error 'slicef-after "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]) (let loop ([xs xs][acc empty])
(if (empty? xs) (match xs
(reverse acc) [(== empty) (reverse acc)]
(match/values (splitf-at xs (negate pred)) [(list* (? (negate pred) not-pred-xs) ... (? pred pred-x) tail)
[(not-pred-xs (cons first-pred-x other-pred-xs)) (loop tail (cons (append not-pred-xs (list pred-x)) acc))]
(loop other-pred-xs (cons (append not-pred-xs (list first-pred-x)) acc))] [tail (loop empty (if force? acc (cons tail acc)))])))
[(not-pred-xs _) not-pred-xs]))))
(define+provide+safe (slice-at xs len [force? #f]) (define+provide+safe (slice-at xs len [force? #f])
((list? exact-nonnegative-integer?) (boolean?) . ->* . (listof list?)) ((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?] [pred procedure?]
[force? boolean? #f]) [force? boolean? #f])
(listof list?)] (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 @examples[#:eval my-eval
(slicef-at (range 5) even?) (slicef-at (range 5) even?)
@ -86,9 +88,12 @@ Divide @racket[_lst] into sublists starting with elements matching @racket[_pred
@defproc[ @defproc[
(slicef-after (slicef-after
[lst list?] [lst list?]
[pred procedure?]) [pred procedure?]
[force? boolean? #f]))
(listof list?)] (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 @examples[#:eval my-eval
(slicef-after '(1 2 2 1 2) even?) (slicef-after '(1 2 2 1 2) even?)

@ -199,6 +199,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?) '((1) (2) (2 1) (2)))
(check-equal? (slicef-at '(1 2 2 1 2) even? #t) '((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 0) '())
(check-equal? (sublist (range 5) 0 1) '(0)) (check-equal? (sublist (range 5) 0 1) '(0))
(check-equal? (sublist (range 5) 0 5) '(0 1 2 3 4)) (check-equal? (sublist (range 5) 0 5) '(0 1 2 3 4))

Loading…
Cancel
Save