From 460504c852c0cbee08c26dd626a4da3ddee33b61 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 9 Jun 2011 16:34:35 -0700 Subject: [PATCH] add `#:unless' to `for' --- collects/racket/private/for.rkt | 12 ++++++++++++ collects/scribblings/guide/for.scrbl | 7 ++++++- collects/scribblings/reference/for.scrbl | 17 +++++++++++------ collects/tests/racket/for-util.rkt | 3 +++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/collects/racket/private/for.rkt b/collects/racket/private/for.rkt index 2bffa68e96..af3a9bc88f 100644 --- a/collects/racket/private/for.rkt +++ b/collects/racket/private/for.rkt @@ -1224,6 +1224,18 @@ (#:when expr . rest) . body) #'(frm [orig-stx nested? #t binds] ([fold-var fold-init] ...) (#:when expr . rest) . body)] + ;; Negative guard case, no pending emits: + [(_ [orig-stx nested? #f ()] ([fold-var fold-init] ...) (#:unless expr . rest) . body) + #'(let ([fold-var fold-init] ...) + (if expr + (values* fold-var ...) + (for/foldX/derived [orig-stx nested? #f ()] + ([fold-var fold-var] ...) rest . body)))] + ;; Negative guard case, pending emits need to be flushed first + [(frm [orig-stx nested? #f binds] ([fold-var fold-init] ...) + (#:unless expr . rest) . body) + #'(frm [orig-stx nested? #t binds] ([fold-var fold-init] ...) + (#:unless expr . rest) . body)] ;; Convert single-value form to multi-value form: [(_ [orig-stx nested? #f binds] fold-bind ([id rhs] . rest) . body) (identifier? #'id) diff --git a/collects/scribblings/guide/for.scrbl b/collects/scribblings/guide/for.scrbl index 481fc40f27..93d9814b3a 100644 --- a/collects/scribblings/guide/for.scrbl +++ b/collects/scribblings/guide/for.scrbl @@ -132,7 +132,8 @@ A more complete syntax of @racket[for] is (for (clause ...) body ...+) ([clause [id sequence-expr] - (code:line #:when boolean-expr)]) + (code:line #:when boolean-expr) + (code:line #:unless boolean-expr)]) ]{} When multiple @racket[[_id _sequence-expr]] clauses are provided @@ -194,6 +195,10 @@ mutually nested, instead of in parallel, even with @racket[for]. (printf "~a Chapter ~a. ~a\n" book i chapter)) ] +An @racket[#:unless] clause is analogus to a @racket[#:when] clause, but +the @racket[_body]s evaluate only when the @racket[_boolean-expr] +produces a false value. + @section{@racket[for/list] and @racket[for*/list]} The @racket[for/list] form, which has the same syntax as @racket[for], diff --git a/collects/scribblings/reference/for.scrbl b/collects/scribblings/reference/for.scrbl index e2f11b6ac4..8a59a1593c 100644 --- a/collects/scribblings/reference/for.scrbl +++ b/collects/scribblings/reference/for.scrbl @@ -14,7 +14,8 @@ The @scheme[for] iteration forms are based on SRFI-42 @defform/subs[(for (for-clause ...) body ...+) ([for-clause [id seq-expr] [(id ...) seq-expr] - (code:line #:when guard-expr)]) + (code:line #:when guard-expr) + (code:line #:unless guard-expr)]) #:contracts ([seq-expr sequence?])]{ Iteratively evaluates @scheme[body]. The @scheme[for-clause]s @@ -45,7 +46,7 @@ a sequence containing a single element. All of the @scheme[id]s must be distinct according to @scheme[bound-identifier=?]. If any @scheme[for-clause] has the form @scheme[#:when guard-expr], -then only the preceding clauses (containing no @scheme[#:when]) +then only the preceding clauses (containing no @scheme[#:when] or @scheme[#:unless]) determine iteration as above, and the @scheme[body] is effectively wrapped as @@ -54,7 +55,9 @@ wrapped as (for (for-clause ...) body ...+)) ] -using the remaining @scheme[for-clauses]. +using the remaining @scheme[for-clauses]. A @scheme[for-clause] of +the form @scheme[#:unless guard-expr] corresponds to the same transformation +with @racket[unless] in place of @racket[when]. @examples[ (for ([i '(1 2 3)] @@ -74,6 +77,9 @@ using the remaining @scheme[for-clauses]. @scheme[for], but that the last expression in the @scheme[body]s must produce a single value, and the result of the @scheme[for/list] expression is a list of the results in order. +When evaluation of a @scheme[body] is skipped due to a @racket[#:when] +or @racket[#:unless] clause, the result list includes no corresponding +element. @examples[ (for/list ([i '(1 2 3)] @@ -89,9 +95,8 @@ expression is a list of the results in order. @defform*[((for/vector (for-clause ...) body ...+) (for/vector #:length length-expr (for-clause ...) body ...+))]{ -Iterates like @scheme[for], but the last expression -in the @scheme[body]s must produce a single value, which is placed in -the corresponding slot of a vector. If the optional @scheme[#:length] +Iterates like @scheme[for/list], but the result are accumulated into +a vector instead of a list. If the optional @scheme[#:length] form is used, then @scheme[length-expr] must evaluate to an @scheme[exact-nonnegative-integer?], and the result vector is constructed with this length. In this case, the iteration can be diff --git a/collects/tests/racket/for-util.rkt b/collects/tests/racket/for-util.rkt index a7def4d645..16ff4478d0 100644 --- a/collects/tests/racket/for-util.rkt +++ b/collects/tests/racket/for-util.rkt @@ -44,6 +44,9 @@ (test (map (lambda (x) #t) `seq) 'gen (for*/list ([i gen][b '(#t)]) b)) (test (append `seq `seq) 'gen (for*/list ([b '(#f #t)][i gen]) i)) (test (append `seq `seq) 'gen (for/list ([b '(#f #t)] #:when #t [i gen]) i)) + (test (append `seq `seq) 'gen (for/list ([b '(#t #t #f)] #:when b [i gen]) i)) + (test (append `seq `seq) 'gen (for/list ([b '(#f #t)] #:unless #f [i gen]) i)) + (test (append `seq `seq) 'gen (for/list ([b '(#f #f #t)] #:unless b [i gen]) i)) (test `seq 'gen (let ([g gen]) (for/list ([i g]) i))) (test `seq 'gen (let ([r null]) (for ([i gen]) (set! r (cons i r)))