add #:result clause to for/lists and for*/lists

This commit is contained in:
Philip McGrath 2018-10-28 17:53:18 -04:00 committed by Matthew Flatt
parent 6d8596bae3
commit b3104a6acd
3 changed files with 79 additions and 23 deletions

View File

@ -258,14 +258,22 @@ is accumulated into a result with @racket[*].
]} ]}
@defform[(for/lists (id ...) (for-clause ...) body-or-break ... body)]{ @defform[(for/lists (id ... maybe-result)
(for-clause ...)
body-or-break ... body)
#:grammar
([maybe-result (code:line) (code:line #:result result-expr)])]{
Similar to @racket[for/list], but the last @racket[body] expression Similar to @racket[for/list], but the last @racket[body] expression
should produce as many values as given @racket[id]s, and the result is should produce as many values as given @racket[id]s.
as many lists as supplied @racket[id]s. The @racket[id]s are bound to The @racket[id]s are bound to
the lists accumulated so far in the @racket[for-clause]s and the lists accumulated so far in the @racket[for-clause]s and
@racket[body]s. @racket[body]s.
If a @racket[result-expr] is provided, it is used as with @racket[for/fold]
when iteration terminates;
otherwise, the result is as many lists as supplied @racket[id]s
@examples[ @examples[
(for/lists (l1 l2 l3) (for/lists (l1 l2 l3)
([i '(1 2 3)] ([i '(1 2 3)]
@ -277,6 +285,13 @@ the lists accumulated so far in the @racket[for-clause]s and
([x '(tvp tofu seitan tvp tofu)] ([x '(tvp tofu seitan tvp tofu)]
#:unless (member x acc)) #:unless (member x acc))
x) x)
(for/lists (firsts seconds #:result (list first seconds))
([pr '((1 . 2) (3 . 4) (5 . 6))])
(values (car pr) (cdr pr)))
]
@history[
#:changed "7.1.0.2" @elem{Added the @racket[#:result] form.}
]} ]}
@ -365,7 +380,7 @@ nested.
@deftogether[( @deftogether[(
@defform[(for*/list (for-clause ...) body-or-break ... body)] @defform[(for*/list (for-clause ...) body-or-break ... body)]
@defform[(for*/lists (id ...) (for-clause ...) body-or-break ... body)] @defform[(for*/lists (id ... maybe-result) (for-clause ...) body-or-break ... body)]
@defform[(for*/vector maybe-length (for-clause ...) body-or-break ... body)] @defform[(for*/vector maybe-length (for-clause ...) body-or-break ... body)]
@defform[(for*/hash (for-clause ...) body-or-break ... body)] @defform[(for*/hash (for-clause ...) body-or-break ... body)]
@defform[(for*/hasheq (for-clause ...) body-or-break ... body)] @defform[(for*/hasheq (for-clause ...) body-or-break ... body)]

View File

@ -540,6 +540,38 @@
[else (values (cons x acc) [else (values (cons x acc)
(hash-set seen x #t))]))]) (hash-set seen x #t))]))])
(list backwards forwards other))) (list backwards forwards other)))
(test '((1 3 5) (2 4 6))
'for/lists-result-clause1
(for/lists (firsts seconds #:result (list firsts seconds))
([pr '((1 . 2) (3 . 4) (5 . 6))])
(values (car pr) (cdr pr))))
(test '((1 3 5) (2 4 6) ())
'for/lists-result-clause2
(let-values ([(firsts seconds other)
(for/lists (firsts
seconds
#:result (values firsts seconds '()))
([pr '((1 . 2) (3 . 4) (5 . 6))])
(values (car pr) (cdr pr)))])
(list firsts seconds other)))
(test '((1 3 5 7 9) (2 4 6 8 10))
'for*/lists-result-clause1
(for*/lists (firsts seconds #:result (list firsts seconds))
([lst '(((1 . 2) (3 . 4) (5 . 6))
((7 . 8) (9 . 10)))]
[pr (in-list lst)])
(values (car pr) (cdr pr))))
(test '((1 3 5 7 9) (2 4 6 8 10) ())
'for*/lists-result-clause2
(let-values ([(firsts seconds other)
(for*/lists (firsts
seconds
#:result (values firsts seconds '()))
([lst '(((1 . 2) (3 . 4) (5 . 6))
((7 . 8) (9 . 10)))]
[pr (in-list lst)])
(values (car pr) (cdr pr)))])
(list firsts seconds other)))
;; for should discard any results and return void ;; for should discard any results and return void
(test (void) 'for-0-values (for ([x '(1 2 3)] [y '(a b c)]) (values))) (test (void) 'for-0-values (for ([x '(1 2 3)] [y '(a b c)]) (values)))

View File

@ -1826,9 +1826,10 @@
(for_/vector stx stx #'for*/vector #'for*/fold/derived #t)) (for_/vector stx stx #'for*/vector #'for*/fold/derived #t))
(define-for-syntax (do-for/lists for/fold-id stx) (define-for-syntax (do-for/lists for/fold-id stx)
(syntax-case stx () (define (do-without-result-clause normalized-stx)
[(_ (id ...) bindings expr1 expr ...) (with-syntax ([(_ (id ...) bindings expr1 expr ...)
(let ([ids (syntax->list #'(id ...))]) normalized-stx])
(define ids (syntax->list #'(id ...)))
(for-each (lambda (id) (for-each (lambda (id)
(unless (identifier? id) (unless (identifier? id)
(raise-syntax-error #f (raise-syntax-error #f
@ -1845,7 +1846,15 @@
expr1 expr1
expr ...)]) expr ...)])
(values* (cons id2 id) ...)))]) (values* (cons id2 id) ...)))])
(values* (alt-reverse id) ...))))])) (values* (alt-reverse id) ...)))))
(syntax-case stx ()
[(_ (id ... #:result result-expr) bindings expr1 expr ...)
#`(let-values ([(id ...)
#,(do-without-result-clause
#'(_ (id ...) bindings expr1 expr ...))])
result-expr)]
[(_ (id ...) bindings expr1 expr ...)
(do-without-result-clause stx)]))
(define-syntax (for/lists stx) (do-for/lists #'for/fold/derived stx)) (define-syntax (for/lists stx) (do-for/lists #'for/fold/derived stx))
(define-syntax (for*/lists stx) (do-for/lists #'for*/fold/derived stx)) (define-syntax (for*/lists stx) (do-for/lists #'for*/fold/derived stx))