[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Mixing syntax-rule and indentifier-syntax

From: Ian Price
Subject: Re: Mixing syntax-rule and indentifier-syntax
Date: Tue, 17 Jan 2012 21:53:48 +0000
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux)

Tobias Brandt <address@hidden> writes:

> Hi,
> is it possible to define a macro that does one thing when
> it's in operator position and another when it's not?
It depends what you mean by that. If you mean operator-position/set!
position/ variable position, then that is id-syntax. If you mean
something like

(define-syntax foo
  (syntax-rules ()
    [(bar foo baz)
     (baz bar)]))

(9 foo sqrt) => (sqrt 9)

then no.

> I want to define a macro `with-vectors` that transforms this:
> (with-vectors (v)
>     (v 0)
>     (set! (v 0) 'foo)
>     (some-procedure v))
> into this:
> (begin
>     (vector-ref v 0)
>     (vector-set! v 0 'foo)
>     (some-procedure v))
> So far I have this:
> (define-syntax with-vectors
>     (syntax-rules ()
>         ((_ (id ...) exp ...)
>          (let-syntax ((id* (syntax-rules ()
>                                ((_ idx) (vector-ref id idx)))) ...)
>              exp ...))))
(define-syntax with-vectors
  (syntax-rules ()
    ((_ (id ...) exp ...)
     (let-syntax ((id (make-variable-transformer
                       (lambda (stx)
                         (syntax-case stx ()
                           [(_ idx) #'(vector-ref id idx)]
                           [idx #'id])))) ...)
       exp ...))))

will cover 
scheme@(guile−user)> (with-vectors (k) (k 0))
$8 = 1
scheme@(guile−user)> (with-vectors (k) (vector-map (lambda (x) (* x x)) k))
$9 = #(1 4 9)

but not the set!, which is slightly trickier. Since the second argument
to set! must be (in an id-macro) an identifier, we need to do that
conversion first, and AFAICS[0] that means turning the macro inside out,
and walking it for set! forms.

What I do is, walk the inner bodies for set! forms, if they are of the
form (set! (foo bar) baz) where foo is a bound vector, I replace them
with (set! foo (bar baz)). I later correct this in the identifier macro
for foo.

(define-syntax with-vectors
  (lambda (stx)
    (syntax-case stx ()
        ((_ (id ...) exp ...)
         #`(with-vectors-helper (id ...)
             #,@(map (lambda (clause)
                      (syntax-case clause (set!)
                        ((set! (arg idx) val)
                         ;; if arg is a bound vector
                         (exists (lambda (x) (bound-identifier=? x #'arg))
                                 #'(id ...))
                         ;; uses original set!, and package up
                         ;; index and value, which we destructure
                         ;; in the id-macro
                         #'(set! arg (idx val)))
                        (id #'id)))
                    #'(exp ...)))))))

(define-syntax with-vectors-helper
  (syntax-rules ()
    ((_ (id ...) exp ...)
     (let-syntax ((id (make-variable-transformer
                       (lambda (stx)
                         (syntax-case stx (set!)
                           [(_ idx) #'(vector-ref id idx)]
                           [(set! id* (idx val))
                            ;; note, it is structured as above
                            #'(vector-set! id idx val)]
                           [idx #'id]))))
       exp ...))))

scheme@(guile−user)> (define k (vector 1 2 3))
scheme@(guile−user)> (with-vectors (k) (list (k 0) (k (k 1))))
$2 = (1 3)
scheme@(guile−user)> (with-vectors (k) (list k (k 1)))
$3 = (#(1 2 3) 2)
scheme@(guile−user)> (with-vectors (k) (set! (k 0) #f) (list (k 0) k))
$4 = (#f #(#f 2 3))
scheme@(guile−user)> k
$5 = #(#f 2 3)

this set! modification only works at the first level of the with-vectors
form, fixing that is left as an exercise :)

0. I'm sure there is another way, but my mind blanks at the moment
Ian Price

"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"

reply via email to

[Prev in Thread] Current Thread [Next in Thread]