|
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