Tobias Brandt <tob.bra...@googlemail.com> 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"