[racket] Help with simple macro
On Wednesday, Harry Spier wrote:
> [...]
> but I've been unable to create a macro to create this form:
> ---------------------------------------
> (with-sequence SOME-SEQUENCE
> . . . .. . (get-next) .
> . . . (get-next) . . . etc.)
> ---------------------------------------
>
> where I don't pass the names of the thunks to test for end of sequence
> or to get the next item in the sequence, but that they are called
> "more?" and "get-next" by convention.
>
> How would I do this.
Since you're using the name as a function, you can do that easily with
a parameter:
(define current-get-next (make-parameter (λ () (error "no next"))))
(define (get-next) ((current-get-next)))
(define-syntax-rule (with-sequence seq body ...)
(let-values ([(more? the-get-next) (sequence-generate seq)])
(parameterize ([current-get-next the-get-next])
body ...)))
(with-sequence '(1 2 3)
(list (get-next) (get-next) (get-next)))
[You could also make it appear as a magical binding with an identifer
macro:
(define-syntax next
(syntax-id-rules ()
[(_ x ...) ((get-next) x ...)]
[_ (get-next)]))
]
This does have some performance penalty though, since each call to
`get-next' goes through the parameter. The way to avoid that is to
switch the parameter to a syntax parameter -- the idea is similar to a
parameter, except that it's done at the syntax level:
(require racket/stxparam)
(define-syntax-parameter get-next
(λ (stx) (raise-syntax-error #f "not in `with-sequence'" stx)))
(define-syntax-rule (with-sequence seq body ...)
(let-values ([(more? the-get-next) (sequence-generate seq)])
(syntax-parameterize ([get-next (make-rename-transformer #'the-get-next)])
body ...)))
(with-sequence '(1 2 3)
(list (get-next) (get-next) (get-next)))
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!