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