[racket] Typed Racket and macros expanding to for*:

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Tue Jul 24 07:33:55 EDT 2012

Hi All,

I am writing a comprehension for*/matrix: that collects
numbers and puts them in an mxn matrix.

A simple example:

(for*/matrix: : Number 2 3 ([i (in-range 6)]) i)
; => '#(0 1 2
;          3 4 5)

In this post the representation is simplified to a vector.

An example more:

(for*/matrix: : Number 2 3
  ([i (in-range 2)]
   [j (in-range 3)])
  (+ (* 10 i) j))
; => '# (   0  1   2
;           10 11 12)

The two examples above work fine with the code below.

However I'd like the comprehension to automatically when m*n
numbers have been generated. That is, I'd like

    (for*/matrix: : Number 2 3 ([i (in-naturals)]) i)

to produce #(0 1 2 3 4 5).

The current expansion generates an index out of range error in vector-set!.
In for/matrix I solved the problem by adding a dummy sequence
before the for:-clauses provided by the macro user.

         (for: ([dummy (in-range (* m n))] for:-clause ...)
           (define x (let () . defs+exprs))

This works because for: evaluates the sequences in parallel.
This also implies I can't use the same trick for for*: which
evaluates the sequences in a nested fashion.

The question is how to modify the expansion below
to  automatically stop after m*n elements have been
generated?

/Jens Axel


#lang typed/racket

(define-syntax (for*/matrix: stx)
  (syntax-case stx ()
    [(_ : type m-expr n-expr (for:-clause ...) . defs+exprs)
     (syntax/loc stx
       (let ()
         (define: m   : Index           m-expr)
         (define: n   : Index           n-expr)
         (define: m*n : Index           (assert (* m n) index?))
         (define: v   : (Vectorof type) (make-vector m*n 0))
         (define: i   : Index           0)
         (for*: (for:-clause ...)
           (define x (let () . defs+exprs))
           (vector-set! v i x)
           (set! i (assert (+ i 1) index?)))
         v))]))

(for*/matrix: : Number 2 3
  ([i (in-range 2)]
   [j (in-range 3)])
  (+ (* 10 i) j))
; => '#(  0  1  2
;        10 11 12)

(for*/matrix: : Number 2 3 ([i (in-range 6)]) i)
; => '#(0 1 2
;       3 4 5)

(for*/matrix: : Number 2 3 ([i (in-naturals)]) i)
; vector-set!: index out of range

Posted on the users mailing list.