[racket] Another macro question: making a lexically binding keyword?

From: Laurent (laurent.orseau at gmail.com)
Date: Wed May 2 05:39:23 EDT 2012

Hi,

I didn't fully read Eli's very detailed answer, so hopefully I won't repeat
what he said.

Here, to me it seems the right approach is to keep hygiene, so that you can
scope your INDEXes as you want, and so that you know exactly what happens
without needing to know the details of `ranged' and `interfere' to know
where your indexes are bound:

#lang racket

(define-syntax ranged
  (syntax-rules ()
    [(_ [i n] body ...)
     (for ([i (in-range n)])
       body ...)]
    [(_ n body ...)
     (ranged [x n] body ...)]))

(define-syntax interfere
  (syntax-rules ()
    [(_ (i) body ...)
     (ranged [i 1] body ...)]
    [(_ () body ...)
     (ranged 1 body ...)]))


(ranged 4
        (interfere (i) (display i)))
(newline)
; -> 0000

(ranged [i 4]
        (interfere () (display i)))
(newline)
; -> 0123

(ranged [i 4]
        (display i)
        (interfere (i) (display i)))
(newline)
; -> 00102030

Then there is no surprise as to how the program works, and you can nest
things as much as you want without worries.

(If you don't like the parentheses for (interfere () ...), you can still
use syntax-parse and check if the first element is an id.)

Laurent


On Sun, Apr 29, 2012 at 9:54 PM, Danny Yoo <dyoo at cs.wpi.edu> wrote:

> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20120502/50b006f7/attachment.html>

Posted on the users mailing list.