[racket] Typed Racket and macros expanding to for*:
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