Scott -- I don't understand exactly what you're asking, at least not based on the example you wrote. You defined x and y, but the error is about z. Is this just a typo? Or are you expecting a value for z to come from somewhere?
Carl Eastlund On Sun, Jan 26, 2014 at 1:01 PM, Scott Klarenbach <sc...@pointyhat.ca>wrote: > Thanks a lot Carl...this is very enlightening. If I could impose one last > question before I go off and digest everything: > > What is the "correct" approach to capturing the runtime values of any > references that may be bound by the enclosing environment, for splicing > into the final recursively-expanded expression? > > ;; example 1 > > (define y 3) > (define x 3) > (define-dsl-syntax (pred? x) (or (= 2 x) (> x y))) > (define-dsl-syntax (bad-pred? x) (or (= 2 x) (> x z))) > > (recursive-expand (pred? 1)) > '(or (= 2 1) (> 1 3)) > > (recursive-expand (bad-pred? 1)) > >> unbound identifier: z > > My naive approach was to collect all the identifiers in the expression > body that had bindings, compare them to the argument list of the macro with > bound-identifier=? to see which ones were explicitly introduced by the > user, and then eval the remaining ones at runtime in a second step in order > to splice them in. > > I haven't tried this, and am sure people are cringing just by reading it, > lol. I know there are tons of features like marking and syntax properties > and origins, etc which I don't yet understand, and which may provide a more > durable solution. > > If needbe, I could explicitly provide to the macro the bindings I wish to > capture, like postgresql does with query params...ie, > > (define-dsl-syntax (pred? x) (or (= 2 x) (> x $1)) #:capture (y)) ;; or > something > > but for obvious reasons it is much better if these expressions just > expanded and automatically captured any referenced values in the same way > as would happen at runtime. > > Thanks a lot. > > Scott. > > > > > On Sat, Jan 25, 2014 at 6:00 PM, Carl Eastlund <carl.eastl...@gmail.com>wrote: > >> Scott, >> >> I see what you're doing now. You're not actually trying to use macro >> expansion at all; you're just using local-expand to substitute the >> definition of pred? where it occurs, so that you can make its macro >> definition also serve as its DSL definition. That's sensible, but >> local-expand is still doing more than you want it to. That's why I put in >> all the expansion caveats -- not because you necessarily meant to do full >> expansion, but because local-expand is pretty explicitly built for full >> expansion, and always tries to push as far as it can. Any time the caveats >> about expansion don't apply, local-expand is probably a bigger gun than you >> need. >> >> Where local-expand is going to bite you is when the definition of pred? >> uses a macro at its top level. For instance: >> >> (define-syntax-rule (pred? x) (or (< x 3) (> x 7))) >> >> Here, local-expand is going to expand the use of (or ...), and any macro >> that (or ...) produces at its top level, until you reach a core form as the >> main expression, or something you've put in an explicit stop list. That's >> not what you want, as I understand it -- you only want to expand pred?. >> >> So what to do when you want to apply one macro, but not perform general >> expansion? Extract its transformer using syntax-local-value, and apply it >> to the expression. You probably also want to apply a syntax mark before >> and after transformation, just to simulate the base level of hygiene the >> macro may be relying on. It might not be necessary for simple definitions, >> but it can't hurt. >> >> I wrote up some code that does this, along with a test showing that it >> won't expand "or" too far. It's also reasonably hygienic -- it won't be >> confused if someone defines a different macro named "pred?", for example. >> I don't know if that's a concern, but again, it can't hurt. Anyway, you >> can find what I wrote here: https://gist.github.com/carl-eastlund/8626893 >> >> Carl Eastlund >> >> On Fri, Jan 24, 2014 at 1:30 PM, Scott Klarenbach <sc...@pointyhat.ca>wrote: >> >>> Just an update, I was able to make this work. >>> >>> #lang racket >>> (require (for-syntax racket/syntax syntax/stx)) >>> >>> (define-syntax-rule (pred? x) (> 3 x)) >>> >>> (define-for-syntax (recursive-expand stx) >>> (let loop ([l (syntax->list stx)]) >>> (cond [(stx-null? l) l] >>> [(stx-pair? (stx-car l)) >>> (cons (loop (stx-car l)) (loop (stx-cdr l)))] >>> [(equal? 'pred? (syntax->datum (stx-car l))) >>> (local-expand (cons (stx-car l) (loop (stx-cdr l))) 'expression #f)] >>> ;; this works >>> [else >>> (cons (stx-car l) (loop (stx-cdr l)))]))) >>> >>> (define-syntax (test stx) >>> (syntax-case stx () >>> [(_ x) >>> (with-syntax ([expanded (recursive-expand #'x)]) >>> #''expanded)])) >>> >>> (module+ test >>> (require rackunit) >>> (check-equal? (test (or (< 10 x) (pred? y))) >>> '(or (< 10 x) (> 3 y)))) >>> >>> The code I couldn't figure out last night was: >>> (local-expand (cons (stx-car l) (loop (stx-cdr l))) 'expression #f)] >>> >>> Thanks. >>> >>> -- >>> Talk to you soon, >>> >>> Scott Klarenbach >>> >>> PointyHat Software Corp. >>> www.pointyhat.ca >>> p 604-568-4280 >>> e sc...@pointyhat.ca >>> 200-1575 W. Georgia >>> Vancouver, BC V6G2V3 >>> >>> _______________________________________ >>> To iterate is human; to recur, divine >>> >> >> > > > -- > Talk to you soon, > > Scott Klarenbach > > PointyHat Software Corp. > www.pointyhat.ca > p 604-568-4280 > e sc...@pointyhat.ca > 200-1575 W. Georgia > Vancouver, BC V6G2V3 > > _______________________________________ > To iterate is human; to recur, divine >
____________________ Racket Users list: http://lists.racket-lang.org/users