[racket] Lazy syntax class attributes

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Fri May 31 16:42:21 EDT 2013

On 05/31/2013 02:47 AM, Eric Dobson wrote:
> I'm working on code (TR optimizer) that needs to match some
> expressions and then compute an attribute based on the expression. I
> would like to abstract this out as a syntax class. Example is below:
>
> #lang racket
> (require syntax/parse)
>
> (define-syntax-class slow
>    (pattern e:expr
>             #:with v (begin (displayln 'slow) #''e)))
>
> (syntax-parse #'(x 2)
>    ((e:slow 1) #'(complicated (form e.v)))
>    ((e:slow 2) #'(complicated (form e.v))))
>
> The issue is that computing the attribute is slow/expensive/effectful
> and so I only want to do the calculation in the case that I use the
> result. One solution is to attach a thunk as the attribute value, but
> this requires changing #'(complicated (form e.v)) to #`(complicated
> (form #,((attribute e.v)))) which quickly becomes less readable with
> many such attributes in the final syntax object. Is there a way to do
> this in a lazy manner that does not complicate the use of the syntax
> class? I'm fine adding complexity to the creation of the syntax class
> because it is a one time cost versus the many places where the syntax
> class would be used.

I've thought about a couple ways of adding laziness, trying to find one 
that doesn't add too much cost or complexity to the system. Here's the 
best idea I've come up with so far.

I could make attribute references in syntax templates automatically 
force their values. (That actually turns out to be a fairly small and 
localized change.) So your syntax class definition would be this instead:

(define-syntax-class slow
     (pattern e:expr
              #:attr v (delay (begin (displayln 'slow) #''e))))

The place where you use the syntax class would stay the same. To 
elaborate, #'e.v forces promises until it hits syntax; (attribute e.v) 
just returns the promise.

Note, however, that the syntax class now uses #:attr instead of #:with. 
That's the main usability issue I'm worried about with this change. 
Following with-syntax's lead, a #:with clause automatically converts its 
right-hand side to syntax---even if the result is "3D". That means that 
if you forget that step of the conversion to laziness, you'll probably 
get bizarre 3D syntax. I could change #:with to raise an error in 
some/all 3D cases, but that might break existing programs.

Is anyone out there using syntax-parse to make 3D syntax?

Ryan


Posted on the users mailing list.