Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I use syntax/loc instead of #' (aka syntax)?

Tags:

racket

A new syntax object can be constructed by both syntax/loc and syntax (also written #').

When should I use syntax/loc?

like image 579
soegaard Avatar asked Jun 02 '12 13:06

soegaard


1 Answers

Use #' (i.e. syntax) when you are not constructing a new syntax object, as when you're just referencing a pattern variable bound with syntax-case or with-syntax.

Use #' for temporary syntax objects as in (syntax->list #'(id ...)).

Use #' for syntax objects representing forms that you know won't have syntax errors in them, or where syntax errors in them are the fault of your macro implementation, not the use of your macro.

Use syntax/loc when you construct expressions that potentially can contain syntax-errors due to an incorrect usage of your macro.

Let's consider a concrete example:

The form display-let should work exactly like normal let, except that it displays the values of the bindings before it evaluates the body.

Here is a first implementation:

(define-syntax (display-let-1 stx)
  (syntax-case stx ()
    [(_ ([id expr] ...) body ...)
     #'((lambda (id ...) 
          (displayln (format "~a is bound to ~a" 'id id)) ...
          body ...)
        expr ...)]))

Here is an example of a correct use of the macro:

> (display-let-1 ([x 1] [y 2]) (+ x y))
x is bound to 1
y is bound to 2
3

Now let us see what happens when the macro is used incorrectly:

> (display-let-1 ())
lambda: bad syntax in: (lambda ())

This usage is incorrect, since a use of let must always have a non-empty body. Besides printing the error message, DrRacket colors this code red:

(lambda (id ...) 
  (displayln (format "~a is bound to ~a" 'id id)) ...
  body ...)

Although it is correct that the lambda expression constructed by the macro is incorrect, (lambda ()) is not legal, it is not due to an error in the macro, but due to an incorrect use of the macro.

To redirect the blame surround the constructed lambda expression with syntax/loc and use the first argument of syntax/loc as place to color red.

(define-syntax (display-let-2 stx)
  (syntax-case stx ()
    [(display-let ([id expr] ...) body ...)
     #`(#,(syntax/loc stx (lambda (id ...) body ...)) expr ...)]))

> (display-let-2 ())
display-let-2: bad syntax in: (display-let-2 ())

This time around the (display-let-2 ()) entered in the repl is colored red, and the error message mentioned display-let-2 instead of lambda.

like image 187
2 revs, 2 users 88% Avatar answered Sep 23 '22 18:09

2 revs, 2 users 88%