guile-user
[Top][All Lists]
Advanced

[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]