Let's say that I have the following toy iteration form for doing
something over a sequence of numbers:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#lang racket

(require racket/stxparam)

(define-syntax (ranged stx)
  (syntax-case stx ()
    [(_ n body ...)
     #'(for ([k n])
         (syntax-parameterize
          ([INDEX (make-rename-transformer #'k)])
          (begin body ...)))]))

(define-syntax-parameter INDEX
  (lambda (stx)
    (raise-syntax-error #f "Used out of context of a ranged" stx)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


This provides INDEX as a way to get at the index used at the kth
iteration.  For example:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (ranged 5 (displayln INDEX))
0
1
2
3
4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



However, as Brian Mastenbrook notes, the use of syntax parameters here
can be troublesome because they don't necessarily work lexically.  For
example, we might be devious and do this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-syntax (interfere stx)
  (syntax-case stx ()
    [(_ body ...)
     #'(ranged 1 body ...)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

The interfere macro here should be a no-op.  However, the use of
'interfere' can interfere with the use of ranged.  As a case in point:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (ranged 5 (interfere (displayln INDEX)))
0
0
0
0
0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



and ideally, I would have liked to see this instead:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (ranged 5 (interfere (displayln INDEX)))
0
1
2
3
4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

I need to do something extra, since the use of interfere adds an
additional syntax parameterization that breaks the lexicalness I
expected from INDEX.



I can do something that appears to do the trick, but I'm a bit
uncomfortable with it:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#lang racket

(require racket/stxparam)

(begin-for-syntax
  (define internal-index-id (gensym 'internal-index-id)))

(define-syntax (ranged stx)
  (syntax-case stx ()
    [(_ n body ...)
     (with-syntax ([k (datum->syntax stx internal-index-id)])
       (syntax/loc stx
         (for ([k n])
           (begin body ...))))]))

(define-syntax (INDEX stx)
  (datum->syntax stx internal-index-id))


(define-syntax (interfere stx)
  (syntax-case stx ()
    [(_ body ...)
     (syntax/loc stx
       (ranged 1 body ...))]))

(ranged 5 (interfere (displayln INDEX)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

The use of the gensym there is what makes me uncomfortable.  I'm not
exactly sure what the right approach is supposed to be here, though.
Suggestions?


Thank you!
____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to