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

A new syntax object can be constructed by both syntax/loc and syntax (also written #').
When should I use syntax/loc?

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.

Related

how can I capture the expanded forms?

I'm trying to capture the expanded forms by defining my own module-begin:
(define-syntax-rule (my-module-begin e ...)
(#%module-begin
e ...
(foo e ...)))
Am I correct that foo here gets the original forms? If so is there a way for foo to get the expanded forms instead?
To get the expanded forms you'll need to use local-expand in some way.
Part 1, an incomplete solution
You might think to call local-expand separately on every expression like this:
#lang racket
(require syntax/parse/define
(for-syntax syntax/stx))
(define-simple-macro (my-module-begin e ...)
; define a function that expands it
#:do [(define (expand/mod-ctx e)
(local-expand e 'module '()))]
; get the expanded versions by calling that function on the e's
#:with (e-expanded ...) (stx-map expand/mod-ctx #'(e ...))
; use the expanded versions inside foo
(#%module-begin
e-expanded ...
(foo e-expanded ...)))
This works when the e forms are expressions like (+ 1 2) or (let ([x 3] [y 4]) (make-list x y)). However, it doesn't work when the e forms can be definitions.
Part 2, getting the expanded versions from Racket's #%module-begin
One way to support using local-expand with these module-level definitions is to wrap it in racket's #%module-begin form before expanding. This allows it to process all the es together in one call to local-expand.
(define-simple-macro (my-module-begin e ...)
; get the expanded versions by calling that function on a
; *constructed* module-begin form
#:with (_ e-expanded ...) (local-expand #'(#%module-begin e ...) 'module-begin '())
; use the expanded versions inside foo
(#%module-begin
e-expanded ...
(foo e-expanded ...)))
This gets Racket's #%module-begin to handle the definitions, and when it's done, you can pattern match on it with (_ e-expanded ...).

Transforming a list of symbols to a list of identifiers to be used in a macro

Consider the scenario where I would like to specify a very simplistic actor language using Racket macros. An actor is defined by a behaviour that defines some local state and message handlers that implement some logic. The body of a message handler can use both the formal parameters of the message, as well as the state variables. An example is implemented in the code below.
There is quite a lot of context in the code which is probably not even necessary. However, I have included it regardless in order to provide a running example, and the fact that I need to use syntax-parametrize may complicate the solution. The special point of interest is the with-syntax clause in the MESSAGE macro, where I require the (local-state-variable ...) pattern to match a list of identifiers, currently #'local-state-variables which is a list of symbols (bound by syntax-parameterize in the ACTOR macro), and thus does not match. So far I have not been able to find the solution, although it does not seem like it should be shockingly difficult. Am I missing something obvious?
#lang racket
(require (for-syntax syntax/parse))
(require racket/stxparam)
(define LOCAL_STATE
(lambda (stx)
(raise-syntax-error 'LOCAL_STATE "should only be used inside an actor" stx)))
; Define some syntax classes because abstractions are nice
(begin-for-syntax
(define-syntax-class actor-local-state
#:description "actor local state"
#:literals (LOCAL_STATE)
(pattern (LOCAL_STATE state-variable:id ...)))
(define-syntax-class message-pattern
#:description "actor message pattern"
(pattern (identifier:id argument:id ...))))
(define-syntax-parameter local-state-variables
(lambda (stx)
(raise-syntax-error 'local-state-variables "reserved keyword for actors" stx)))
(define-syntax (MESSAGE stx)
(syntax-parse stx
[(_ pattern:message-pattern body:expr ...+)
; Currently there is a "binding match failed" error on the following line, but replacing #'local-state-variables with #'(a b) (a list of identifiers) needless to say works.
(with-syntax ([(local-state-variable ...) #'local-state-variables])
; For simplicity just display the state variables - this is normally where some magic happens
#'(display '(local-state-variable ...)))]))
(define-syntax (ACTOR stx)
(syntax-parse stx
[(_ state:actor-local-state handler:expr ...+)
#'(syntax-parameterize
([local-state-variables '(state.state-variable ...)])
; For the sake of simplicity, an actor is currently a list of message handlers
(list handler ...))]))
; in this proof-of-concept code this should print (a b)
(define behaviour
(ACTOR (LOCAL_STATE a b)
(MESSAGE (add x y) (+ a b x y))))
Use syntax-parameter-value. Here's an example of using syntax parameters to manage lists of variables:
;; vars : syntax parameter of (Listof Identifier)
(define-syntax-parameter vars null)
;; with-vars: like let, but set vars
(define-syntax (with-vars stx)
(syntax-parse stx
[(_ ([var:id rhs:expr] ...) . body)
#'(let ([var rhs] ...)
(syntax-parameterize ([vars (list (quote-syntax var) ...)])
. body))]))
;; get-vars: get vars (symbolic name) and their values
(define-syntax (get-vars stx)
(syntax-parse stx
[(_)
(with-syntax ([(var ...) (syntax-parameter-value #'vars)])
#'(list (list (quote var) var) ...))]))
;; Examples:
(get-vars)
;; => '()
(with-vars ([x 1])
(get-vars))
;; => '((x 1))
(with-vars ([x 1])
(with-vars ([y 2] [z 3])
(set! z 17)
(get-vars)))
;; => '((y 2) (z 17))
The easiest way to turn any datum (including a list of symbol) into an identifier with datum->syntax. (You can also use format-id, but that works on only a single identifier.) With these functions, you pass in a syntax object for the scopes you want your new identifier to have, or #f if you want it to inherit the scopes that your current macro is generating.1 Getting your list of identifiers (as one single syntax object, would just be:
(syntax->datum stx '(a b c))
Where '(a b c) is your list of identifiers. Finally, you can then add this in your with-syntax:
(with-syntax ([(local-state-variables ...) (datum->syntax stx ...)])
...)
As a side note, the way to answer the title of your question, just iterate over your list with map producing a new list using format-id:
(map (curry format-id stx "~a") '(a b c)
1Unless I'm wrong, if so, please correct this.

Defining a nested racket macro with access to surrounding variables

I have a macro that extends the racket syntax, and at some point accepts a sequence of bog standard racket expressions. This looks something like this, the relevant syntax variable being body:
(syntax-parse stx
[(_ some-id:id
body:expr ...+)
This macro generates a racket class with a generated method like so:
#'(<class stuff>
(define/public (some-id some-formal-parameter)
body ...)
As I said the body is plain racket code, except for one expression that can be used exclusively in the body, for example:
(define-syntax-rule (tweet identifier value)
(send this publish-tweet (quote identifier) value))
But this does not allow me to use some-formal-parameter because it is not defined. Is there some proper way in which I can define something that can exclusively be used in the body, and can still bind to variables in the context after expansion? Maybe via a splicing syntax class? Reusability is a big bonus, since this "type of body" may exists in multiple (similar) macros.
Some code for testing:
#lang racket
(require (for-syntax syntax/parse))
(define-syntax (define-something stx)
(syntax-parse stx
[(_ some-id:id
body:expr ...+)
#'(define some-id
(new
(class object%
(super-new)
(define/public (displ arg)
(displayln arg))
(define/public (tick some-formal-parameter)
body ...))))]))
(define-syntax-rule (tweet value)
(send this displ value))
(define-something derp
(define a 'not-derp)
(tweet a))
(send derp tick 'derp)
To reformulate the original question now that I know (and can answer) what I wanted to ask: how can I define a macro that can only be used in a certain context (for me: in the body of a method of a racket class), and how can I use dynamically bound variables. In the original code above: when using the expression (tweet a) not only do I want the value of a, but also the value of some-formal-parameter which is bound in the context of the code where the tweet macro is expanded (not where it is defined).
Chris Jester-Young kindly pointed me to syntax parameters, which indeed seem to solve both the issue of dynamic binding and "can only be used in certain contexts". A paper by Eli Barzilay, Ryan Culpepper, and Matthew Flatt helped me understand syntax parameters.
With respect to the original example code I posted, this is the solution I have come up with:
#lang racket
(require
racket/stxparam
(for-syntax syntax/parse))
(define-syntax-parameter tweet
(lambda (stx)
(raise-syntax-error 'tweet "use of an actor keyword outside of the body of an actor" stx)))
(define-syntax (define-something stx)
(syntax-parse stx
[(_ some-id:id
body:expr ...+)
#'(define some-id
(new
(class object%
(super-new)
(define/public (tick some-formal-parameter)
(syntax-parameterize
([tweet
(syntax-rules ()
[(_ value)
(begin (displayln some-formal-parameter)
(displayln value))])])
body ...)
))))]))
(define-something derp
(define a 'not-derp)
(tweet a))
(send derp tick 'derp)
The three key points of attention are the following.
Because of the definition of the tweet macro, whenever it is used outside of the context of a syntax-parametrize statement (that changes the definition of tweet) it will throw an appropriate error.
In the body of the public method tick of our class we change thedefinition of tweet to a macro that matches a pattern of the form (_ value) (which is the value we supply to tweet)
The tweet macro can expand to something that both uses the bound value value, and the value of some-formal-parameter, whatever that may be.
I do not know if this is the proper way to deal with such a situation, but it seems good.

Scheme macros with 2 params

Can I define macro that will get one param from left and one from right part of macro? I want to write some kind of this in my programs:
(test = 10)
to define new variables
I tried to write that macro:
(define-syntax =
(syntax-rules ()
((a _ b)
(define a b))))
But I've got error "bad syntax in: ="
Since the form is determined by the first element you'd have problems with test not being bound.
The right way is this:
(= test 10)
You write the macro like this:
(define-syntax =
(syntax-rules ()
((_ a b) (define a b))))
There you go. Without horrible infix syntax.

Racket macros - making pairs

I've just started diving into Racket macros, and am trying to make a terse simple-macro-defining macro. I would like to expand an expression like this:
(macro id
(param) replacement1
(params ...) replacement2)
Into something like this:
(define-syntax id
(syntax-rules ()
((id param) replacement1)
((id params ...) replacement2)))
So the cddr of the original expression is turned into pairs of expressions (for use in the syntax-rules body), and the id is inserted into the car of each of these pairs.
I'm having trouble thinking recursively when using only the pattern-matching provided by syntax-rules (I keep wanting to manipulate the expression as though it were a normal list). What kind of pattern should I use? Or, can I somehow manipulate it as a normal list, and then unquote the result for use in the expansion?
Many thanks
Edit - tentative solution, informed by Taymon's answer
Part of my curiosity here was about getting rid of those pairing parentheses. I looked into syntax-case, but got a bit confused, so tried to do it purely with the pattern-matching sub-language. I ended up using Taymon's macro combined with another macro to 'pairize' the given templates (it acts kind of like an accumulator function):
(define-syntax-rule (macro-aux id ((param ...) expr) ...)
(define-syntax id
(syntax-rules ()
((id param ...) expr)
...)))
(define-syntax pairize
(syntax-rules ()
((pairize id (pairs ...) p b) (macro-aux id pairs ... (p b)))
((pairize id (pairs ...) p b rest ...) (pairize id (pairs ... (p b)) rest ...))))
(define-syntax macro
(syntax-rules ()
((macro id tpl-expr ...) (pairize id () tpl-expr ...))))
It is possible to build a macro expander that manipulates the syntax expression as regular Racket data. However, that's not really necessary in this case.
One thing I would recommend is changing your syntax slightly, so that each pattern-replacement pair is enclosed in brackets. Like this:
(macro id
[(param) replacement1]
[(params ...) replacement2])
Once that's done, you can just use a regular pattern-matching macro. Here's my take on it:
(define-syntax-rule (macro id [(param ...) replacement] ...)
(define-syntax id
(syntax-rules ()
[(id param ...) replacement] ...)))
Taymon is right, but it is also possible to do it with ellipses without wrapping the pattern-replacement pairs in brackets, using ~seq from syntax/parse:
(require syntax/parse/define)
(define-simple-macro (macro id (~seq (param ...) replacement) ...)
(define-syntax id
(syntax-rules ()
[(id param ...) replacement] ...)))
Which can be used like you originally wanted:
(macro id
(param) replacement1
(params ...) replacement2)