[racket] Introduction to syntax-parse

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Wed Sep 25 01:19:23 EDT 2013

You really do need to know a little bit about phases in order to develop 
macros in Racket, so just putting a band-aid on the issue wouldn't be 
much help, and the apparent departure from the normal rules would just 
make it more difficult to understand phases by looking at the requires 
of a working program.

For example, you might expect this to work:

   (require 'sp)

   (define-syntax-class binding
     (pattern (var:id rhs:expr)))

   (define-syntax (mylet stx)
     (syntax-parse stx
       [(_ (b:binding ...) body ...+)
        #'((lambda (b.var ...) body ...) b.rhs ...)]))

But it doesn't, because binding is a phase-0 syntax class and the macro 
needs a phase-1 syntax-class. You still have to think about phases.

Compare with:

   (require (for-syntax syntax/parse))

   (begin-for-syntax
    (define-syntax-class binding
      (pattern (var:id rhs:expr))))

   (define-syntax (mylet stx)
     (syntax-parse stx
       [(_ (b:binding ...) body ...+)
        #'((lambda (b.var ...) body ...) b.rhs ...)]))

The syntax-parse library is required at phase 1 (with for-syntax). The 
define-syntax-class form is used at phase 1 (in a begin-for-syntax). The 
syntax-parse form is used at phase 1 (rhs of define-syntax). They're all 
consistent.

IMO, the clarity is worth the extra verbiage.

Ryan


On 09/24/2013 03:20 PM, Nick Sivo wrote:
> Why doesn't syntax/parse just provide everything at phases 0 and 1
> like the module 'sp below:
>
> (module sp racket/base
>    (require syntax/parse
>             (for-syntax syntax/parse))
>    (provide (all-from-out syntax/parse)
>             (for-syntax (all-from-out syntax/parse))))
>
> (require 'sp)
>
> (define-syntax (mylet stx)
>    (syntax-parse stx
>                  [(_ ([var-id rhs-expr] ...) body ...+)
>                   #'((lambda (var-id ...) body ...) rhs-expr ...)]))
>
> I've not done as much Racket programming as many of you, but I've yet
> to want syntax/parse in only phase 0.
>
> -Nick
>
> On Tue, Sep 24, 2013 at 10:21 AM, Laurent <laurent.orseau at gmail.com> wrote:
>> This is a quite common pitfall into which I have myself fallen a few times,
>> and I guess it's not the last time.
>>
>> How much work would be required to prevent people from falling into it ever
>> again?
>> Maybe saying so in the docs at the right place wouldn't hurt, but people may
>> still miss it.
>> Maybe making the error message more specific like "Did you forget to
>> (require (for-syntax syntax/parse)) ?" ? Or is it too specific?
>> Or pushing the idea further (and requiring more work, obviously), Racket's
>> errors could propose a list of packages where the unknown identifier can be
>> found, along with the require phase? Is xref able to do that currently?
>>
>> Laurent
>>
>>
>>
>> On Tue, Sep 24, 2013 at 6:20 PM, Stephen Chang <stchang at ccs.neu.edu> wrote:
>>>
>>> You need (require (for-syntax syntax/parse)) because you are using it
>>> inside a define-syntax.
>>>
>>> On Sep 24, 2013 11:56 AM, "Konrad Hinsen" <konrad.hinsen at fastmail.net>
>>> wrote:
>>>>
>>>> Hi everyone,
>>>>
>>>> I am trying to learn about syntax-parse, starting with the introduction
>>>> of the "Syntax" documentation.
>>>>
>>>> Unfortunately, the very first example given for the use of syntax-parse
>>>> doesn't work in my Racket installation:
>>>>
>>>>     Welcome to Racket v5.90.0.9.
>>>>     racket@> (require syntax/parse)
>>>>     racket@> (define-syntax (mylet stx)
>>>>                  (syntax-parse stx
>>>>                    [(_ ([var-id rhs-expr] ...) body ...+)
>>>>                     #'((lambda (var-id ...) body ...) rhs-expr ...)]))
>>>>     stdin::277: _: wildcard not allowed as an expression
>>>>       in: (_ ((var-id rhs-expr) ...) body ...+)
>>>>       errortrace...:
>>>>       context...:
>>>>        try-next
>>>>
>>>> /Users/hinsen/Development/racket/pkgs/errortrace-pkgs/errortrace-lib/errortrace/errortrace-lib.rkt:480:4
>>>>
>>>> /Users/hinsen/Applications/Racket/collects/racket/private/misc.rkt:87:7
>>>>
>>>> I tried replacing the wildcard by "mylet", but that only leads to another
>>>> error
>>>> message:
>>>>
>>>>     racket@> (define-syntax (mylet stx)
>>>>                  (syntax-parse stx
>>>>                    [(mylet ([var-id rhs-expr] ...) body ...+)
>>>>                     #'((lambda (var-id ...) body ...) rhs-expr ...)]))
>>>>     stdin::842: ...: ellipses not allowed as an expression
>>>>       in: ...
>>>>       errortrace...:
>>>>       context...:
>>>>        try-next
>>>>
>>>> /Users/hinsen/Development/racket/pkgs/errortrace-pkgs/errortrace-lib/errortrace/errortrace-lib.rkt:480:4
>>>>
>>>> /Users/hinsen/Applications/Racket/collects/racket/private/misc.rkt:87:7
>>>>
>>>> Am I doing something wrong here? Or are the examples obsolete?
>>>>
>>>> Konrad.
>>>> ____________________
>>>>    Racket Users list:
>>>>    http://lists.racket-lang.org/users


Posted on the users mailing list.