for-helpers
1 APIs
in-mapped
in-filtered
1.1 Performance Notes
2 More APIs
in-filter&map
in-lists
in-nested
2.1 Performance Notes for for-helpers/  extra
3 Composing Multiple Values
8.12

for-helpers🔗ℹ

yjqww6

Helper macros for racket/for.

1 APIs🔗ℹ

 (require for-helpers) package: for-helpers

syntax

(in-mapped proc sequence ...+)

Returns a sequence similar to
(in-generator
 (let ([p proc])
   (for ([s sequence] ...)
     (call-with-values
      (λ () (p s ...))
      yield))))
, without touching continuations or building intermediate sequences.

This macro cannot be used outside for clauses.

Examples:
> (for/list ([(a b)
              (in-mapped
               (match-lambda [(cons a b) (values a b)])
               '((1 . 2) (3 . 4) (4 . 5)))])
    (cons a b))

'((1 . 2) (3 . 4) (4 . 5))

> (for/list ([a (in-mapped cons
                           (in-mapped cons
                                      (in-range 5)
                                      (in-range 5 10))
                           (in-mapped cons
                                      (in-range 10 15)
                                      (in-range 15 20)))])
    a)

'(((0 . 5) 10 . 15)  ((1 . 6) 11 . 16)  ((2 . 7) 12 . 17)  ((3 . 8) 13 . 18)  ((4 . 9) 14 . 19))

syntax

(in-filtered pred sequence ...+)

Returns a sequence similar to
(in-generator
 (let ([p pred])
   (for ([s sequence] ...
         #:when (p s ...))
     (yield s ...))))
, without touching continuations or building intermediate sequences.

This macro cannot be used outside for clauses.

Examples:
> (for/list ([(a b) (in-filtered <
                                 '(1 3 5 -1)
                                 (in-list '(6 4 2 0)))])
    (cons a b))

'((1 . 6) (3 . 4) (-1 . 0))

> (for/list ([a (in-filtered odd? (in-range 5))]
             [b (in-filtered even? (in-range 5))])
    (cons a b))

'((1 . 0) (3 . 2))

1.1 Performance Notes🔗ℹ

Due to the limitations of code structures of :do-in, in-mapped and in-filtered do not compose well without optimizations. This package does optimize nested forms, which should cover most use cases. See tests/bench.rkt.

Examples:
> (optimize
   [(a) (in-filtered positive?
                     (in-filtered even?
                                  (in-range -5 5)))])

((a)

 (in-filtered

  (let ((positive?30 positive?))

    (let ((even?31 even?)) (λ (v29) (and (even?31 v29) (positive?30 v29)))))

  (in-range -5 5)))

> (optimize
   [(a) (in-mapped cons
                   (in-mapped cons
                              (in-range 500)
                              (in-range 500 1000))
                   (in-mapped cons
                              (in-range 1000 1500)
                              (in-range 1500 2000)))])

((a)

 (in-mapped

  (let ((cons33 cons))

    (let ((cons34 cons))

      (let ((cons37 cons))

        (λ (tmp35 tmp36 tmp38 tmp39)

          (cons33 (cons34 tmp35 tmp36) (cons37 tmp38 tmp39))))))

  (in-range 500)

  (in-range 500 1000)

  (in-range 1000 1500)

  (in-range 1500 2000)))

> (optimize
   [(a) (in-filtered
         odd?
         (in-mapped add1
                    (in-filtered
                     even?
                     (in-mapped (λ (v) (* 2 v))
                                (in-range 10)))))])

((a)

 (in-filter&map

  (let ((odd?42 odd?))

    (let ((add143 add1))

      (let ((even?45 even?))

        (let ((temp46 (λ (v) (* 2 v))))

          (λ (v40)

            (let ((tmp44 (temp46 v40)))

              (if (even?45 tmp44)

                (let ((tmp41 (add143 tmp44)))

                  (if (odd?42 tmp41) (values #t tmp41) (values #f #f)))

                (values #f #f))))))))

  (in-range 10)))

Currently, it is not suggested to define something like in-filter-mapped as (in-filtered values (in-mapped _ ...)) using define-sequence-syntax, since there is no partial expansion support from expand-for-clause, which disables potential optimizations when nested.

2 More APIs🔗ℹ

 (require for-helpers/extra) package: for-helpers

syntax

(in-filter&map proc sequence ...+)

Returns a sequence similar to
(in-generator
 (let ([p proc])
   (for ([s sequence] ...)
     (let-values ([(ok x ...) (proc s ...)])
       (when ok
         (yield x ...))))))
, without touching continuations or building intermediate sequences.

This macro cannot be used outside for clauses.

Example:
> (for/list ([(a b) (in-filter&map (λ (a b)
                                     (values (< a b) (+ a b) (- a b)))
                                   (in-list '(1 3 5 -1))
                                   (in-list '(6 4 2 0)))])
    (cons a b))

'((7 . -5) (7 . -1) (-1 . -1))

syntax

(in-lists sequence)

Returns a sequence similar to
(in-generator
 (for* ([s sequence]
        [x (in-list s)])
   (yield x)))
, without touching continuations or building intermediate sequences.

This macro cannot be used outside for clauses.

Example:
> (for/list ([x (in-lists (in-lists (in-list '(((1 2 3) (4 5 6))
                                               ((7 8 9) (a b c))))))])
    x)

'(1 2 3 4 5 6 7 8 9 a b c)

syntax

(in-nested ([(s ...) sequences] ...) sequence)

Returns a sequence similar to
(in-generator
 (for* ([(s ...) sequences] ...
        [(x ...) sequence])
   (yield x ...)))
, without touching continuations or building intermediate sequences.

This macro cannot be used outside for clauses.

Example:
> (for/list ([a (in-nested
                 ([(b) (in-list '((0) (1 2 3) (4 5)))]
                  [(x) (in-list b)])
                 (in-range x))])
    a)

'(0 0 1 0 1 2 0 1 2 3 0 1 2 3 4)

Warning: This macro may bloat your code.

2.1 Performance Notes for for-helpers/extra🔗ℹ

Benchmarks show in RacketCS, the performance of in-lists is nearly optimal, and in-nested is also reasonably good. But unfortunately, it seems RacketBC doesn’t properly optimize these forms, which results in poor performance.

3 Composing Multiple Values🔗ℹ

For forms supporting multiple sequence inputs, n consecutive _ can be specified to indicating the followed sequence returns n+1 values.

Examples:
> (for/list ([a (in-mapped +
                           (in-hash #hash((1 . 2)
                                          (3 . 4)))
                           _)])
    a)

'(3 7)

> (for/list ([(a b) (in-filtered (λ (a b) (odd? a))
                                 (in-hash #hash((1 . 3)
                                                (2 . 4)))
                                 _)])
    (list a b))

'((1 3))