Creating a New SRFI-42 Generator
You have a new datatype, in this example a
matrix, and you want users to be able to iterate over it using
SRFI-42.
You should define your own
typed generator, just like
:vector,
:list, etc. Assume that the functions
matrix-rows,
matrix-cols, and
matrix-ref are defined for getting the dimensions and elements of a matrix. You should define a new syntax transformer which expands into an instance of
:do (or any other generator, if your needs are simple):
(define-syntax :matrix
(syntax-rules (index)
((:matrix cc x (index i j) mexpr)
(:do cc
(let ((m mexpr)
(rows #f)
(cols #f))
(set! rows (matrix-rows m))
(set! cols (matrix-cols m)))
((i 0) (j 0))
(< i rows)
(let ((x (matrix-ref m i j))
(i+1 (+ i 1))
(j+1 (+ j 1))
(wrap? #f))
(set! wrap? (>= j+1 cols)))
#t
((if wrap? i+1 i)
(if wrap? 0 j+1))))
((:matrix cc x mexpr)
(:matrix cc x (index i j) mexpr))))
The macros in
SRFI-42 are all written using CPS; the
cc argument contains the "continuation" form which will continue the expansion of the loop after this generator has been handled.
The
:do generator expands into
(:do (let (<ob>*) <oc>*) (<lb>*) <ne1?> (let (<ib>*) <ic>*) <ne2?> (<ls>*))
=>
(let (<ob>*)
<oc>*
(let loop (<lb>*)
(if <ne1?>
(let (<ib>*)
<ic>*
payload
(if <ne2?>
(loop <ls>*) )))))
allowing us to write "named-let" loops with our macro. (Note that we have to pass the
cc argument to
:do inside our macro, even though it doesn't appear in the expansion above.)
So, the
:matrix generator expands into
(:matrix x (index i j) M)
=>
(let ((m matrix)
(rows #f)
(cols #f))
(set! rows (matrix-rows m))
(set! cols (matrix-cols m))
(let loop ((i 0) (j 0))
(if (< i rows)
(let ((x (matrix-ref m i j))
(i+1 (+ i 1))
(j+1 (+ j 1))
(wrap? #f))
(set! wrap? (>= j+1 cols))
(if #t
(begin
(do-payload ...)
(loop (if wrap? i+1 i)
(if wrap? 0 j+1))))))))
which is exactly the "named-let" loop we would have written to iterate over the elements of
matrix in row-major order.
Note that we supply both an
(index i j) and non-indexed generator form, where
index is a
syntax-rules literal.
--
WillFarr - 24 Aug 2007
The equivalent definition of :matrix in the reimplementation of srfi-42 is as follows:
(require (planet "42.ss" ("soegaard" "srfi.plt" 2 1)))
(define matrix-rows length)
(define (matrix-cols x) (length (car x)))
(define (matrix-ref m i j) (list-ref (list-ref m i) j))
(define-generator :matrix
(lambda (form-stx)
(syntax-case form-stx (index)
[(:matrix x mexpr)
#'(:matrix x (index i j) mexpr)]
[(:matrix x (index i j) mexpr)
#'(:do (let ((m mexpr)
(rows #f)
(cols #f))
(set! rows (matrix-rows m))
(set! cols (matrix-cols m)))
((i 0) (j 0))
(< i rows)
(let ((x (matrix-ref m i j))
(i+1 (+ i 1))
(j+1 (+ j 1))
(wrap? #f))
(set! wrap? (>= j+1 cols)))
#t
((if wrap? i+1 i)
(if wrap? 0 j+1)))])))
(define M '((1 2 3)
(4 5 6)))
(list-ec (:matrix x (index i j) M)
(list x i j))
((1 0 0) (2 0 1) (3 0 2) (4 1 0) (5 1 1) (6 1 2))
Note that the "mysterious" cc disappeared.
--
JensAxelSoegaard - 24 Aug 2007