From 297a93767b9356ba65b0798e16da6b5a93c92cc4 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Tue, 19 Mar 2019 15:11:34 -0700 Subject: [PATCH] fix `slicef-after` --- sugar/list.rkt | 27 ++++++++++++++------------- sugar/scribblings/list.scrbl | 11 ++++++++--- sugar/test/main.rkt | 8 ++++++++ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/sugar/list.rkt b/sugar/list.rkt index 6a4cac5..b6ba3b7 100644 --- a/sugar/list.rkt +++ b/sugar/list.rkt @@ -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?)) diff --git a/sugar/scribblings/list.scrbl b/sugar/scribblings/list.scrbl index 3982201..ec727d8 100644 --- a/sugar/scribblings/list.scrbl +++ b/sugar/scribblings/list.scrbl @@ -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?) diff --git a/sugar/test/main.rkt b/sugar/test/main.rkt index 7548909..8f68a91 100644 --- a/sugar/test/main.rkt +++ b/sugar/test/main.rkt @@ -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))