Initial comments & questions
campbell@xxxxxx
(18 Mar 2004 23:07 UTC)
|
||
Re: Initial comments & questions
campbell@xxxxxx
(19 Mar 2004 00:45 UTC)
|
||
Re: Initial comments & questions
Andre van Tonder
(20 Mar 2004 03:06 UTC)
|
||
(missing)
|
||
Re: Initial comments & questions Alex Shinn (31 Mar 2004 07:30 UTC)
|
||
Re: Initial comments & questions
Alex Shinn
(31 Mar 2004 08:33 UTC)
|
||
Re: Initial comments & questions
Andre van Tonder
(31 Mar 2004 19:14 UTC)
|
At Tue, 23 Mar 2004 10:00:18 -0800 (PST), xxxxxx@autodrip.bloodandcoffee.net wrote: > > > > - Very little is mentioned about hygiene, which I'm worried about. > > > - Very little is mentioned about shadowing. > > > > I'll see if I can come up with something intelligent to say about this. > > I expect the reason you're avoiding those mentions is that you're > assuming the underlying SYNTAX-RULES implementation deals with them, > but I think this is a dangerous assumption that could potentially cause > _very_ unportable code. But syntax-rules hygiene can already be broken, and computation-rules just gives you more ways to do so. What more can be said? As an example, suppose we want to implement with-slots from CLOS: (with-slots (name1 name2 ...) obj ...) where name1 is bound to (slot-ref obj 'name1) in the body of the form. For the sake of those not using a CLOS-like system we'll use the following for our examples: (define (slot-ref obj slot) (vector-ref obj (case slot ((a) 0) ((b) 1) ((c 2)) ((d 3))))) (define my-obj #(1 10 100 1000)) First we want a syntax-replace macro: (define-syntax-computation syntax-equal? (computation-rules () ((syntax-equal? (h1 . t1) (h2 . t2)) (syntax-if (syntax-equal? h1 h2) (syntax-equal? t1 t2) (syntax-return #f))) ((syntax-equal? #(h1 t1 ...) #(h2 t2 ...)) (syntax-if (syntax-equal? h1 h2) (syntax-equal? (t1 ...) (t2 ...)) (syntax-return #f))) ((syntax-equal? x y) (syntax-eq? x y)))) (define-syntax-computation syntax-list->vector (computation-rules () ((syntax-list->vector ls) (syntax-do (rev <- (syntax-reverse ls)) (syntax-list->vector rev #()))) ((syntax-list->vector () #(v1 ...)) (syntax-return #(v1 ...))) ((syntax-list->vector (h . t) #(v1 ...)) (syntax-list->vector t #(h v1 ...))) )) (define-syntax-computation syntax-replace (computation-rules () ((syntax-replace from to (h . t)) (syntax-if (syntax-equal? (h . t) from) (syntax-return to) (syntax-do (h1 <- (syntax-replace from to h)) (t1 <- (syntax-replace from to t)) (syntax-return (h1 . t1))))) ((syntax-replace from to #(h t ...)) (syntax-if (syntax-equal? #(h t ...) from) (syntax-return to) (syntax-do (h1 <- (syntax-replace from to h)) (t1 <- (syntax-replace from to (t ...))) (syntax-return (syntax-list->vector (h1 . t1)))))) ((syntax-replace from to s) (syntax-if (syntax-equal? s from) (syntax-return to) (syntax-return s))) )) Then the implementation is straightforward: (define-syntax-computation with-slots-computation (computation-rules () ((with-slots-computation () obj . body) (syntax-return (begin . body))) ((with-slots-computation (slot1 slot2 ...) obj . body) (syntax-do (inner1 <- (with-slots-computation (slot2 ...) obj . body)) (inner2 <- (syntax-replace slot1 tmp inner1)) (syntax-return (let ((tmp (slot-ref obj 'slot1))) inner2)))))) (define-syntax with-slots (syntax-rules () ((with-slots slots obj . body) (syntax-run (with-slots-computation slots obj . body))))) And our example works as expected: (syntax-inspect (with-slots-computation (a b c) my-obj (+ a b c))) => (let ((tmp (slot-ref my-obj 'a))) (let ((tmp (slot-ref my-obj 'b))) (let ((tmp (slot-ref my-obj 'c))) (begin (+ tmp tmp tmp))))) (with-slots (a b c) my-obj (+ a b c)) => 111 The nested tmp bindings don't interfere with each other as expected. If we bind tmp in the body we're safe as well: (with-slots (a b c) my-obj (let ((tmp 5)) (+ a b c))) => 111 Macros inside the body may safely expand into forms using tmp or any of the replaced symbols: (define-syntax add (syntax-rules () ((add) 0) ((add x) x) ((add x y z ...) (let ((a (+ x y))) (add a z ...))))) (with-slots (a b c) my-obj (let ((tmp 5)) (add a b c))) => 111 Also rebinding the slot names in the body works as you would expect: (with-slots (a b c) my-obj (let ((a 5)) (add a b c))) => 115 The bad news? The above computations take about 10 _minutes_ each on Petite Chez. I would not want to try this on MzScheme if it was "very slow" in comparison to Chez! -- Alex