In a custom Racket language, how can I define a recursive macro? - macros

I am trying to create a recursive macro in a custom Racket language.
However, while the macro expands properly with #lang racket, it fails when implemented with my new language.
For example, here is the recursive definition of a simple macro f which expands to its last argument:
;; my-lang.rkt
#lang racket
(provide #%datum
#%module-begin
define-syntax
(for-syntax syntax-case
syntax
raise-syntax-error
#%app
quote
#%datum))
#lang s-exp "my-lang.rkt"
(define-syntax (f stx)
(syntax-case stx ()
[(_ x) #'x]
[(_ x xs ...) #'(f xs ...)]
[_ (raise-syntax-error 'f "bad syntax" stx)]))
(f 1 2 3) ; => f: bad syntax in: (f 2 3)
Why isn't (f 2 3) matched and expanded?

Add ... to the provided identifiers.
#lang racket
(provide #%datum
#%module-begin
define-syntax
(for-syntax syntax-case
syntax
raise-syntax-error
#%app
quote
quote-syntax
...
#%datum))

Related

unbound variable in racket macro

I am testing a wrapper macro around the racket syntax-case macro. At step 1, it does nothing interesting and simply passes through all the parts to syntax-case directly as follows:
#lang racket
;; definition
(define-syntax guarded-syntax-case
(lambda (x)
(syntax-case x ()
((guarded-syntax-case y (literal ...) clause ...)
#'(syntax-case y (literal ...) clause ...)
))))
;; test case
(define-syntax (binop stx)
(guarded-syntax-case stx () ; *problem site*
[(_ op n1 n2) #'(op n1 n2)]))
But this simple case fails with the following error at the empty brackets () labeled with problem site labeled in above code:
; ....rkt:11:27: #%app: missing procedure expression;
; probably originally (), which is an illegal empty application
; after encountering unbound identifier (which is possibly the real problem):
; guarded-syntax-case
; in: (#%app)
I couldn't figure out what could be wrong in this simple pass-through macro. The error message seems to suggest that there is a unbound variable somewhere, which I couldn't identify. I would think that the literal ... should be matched to empty.
Could someone help explain what went wrong and how to fix the macro?
The problem is that guarded-syntax-case is not recognized as a macro in the correct phase. In particular, when you (define-syntax guarded-syntax-case ...) in your program, you define the macro guarded-syntax-case that is available in phase 0. But forms in (define-syntax (binop stx) ...) must be in phase 1.
There are two ways to correct the mistake.
You can wrap (define-syntax guarded-syntax-case ...) inside begin-for-syntax. However, doing so would require syntax-case and other stuff to be available in phase 2. So you need an additional (require (for-meta 2 racket/base)). Here's the full code:
#lang racket
(require (for-meta 2 racket/base))
;; definition
(begin-for-syntax
(define-syntax guarded-syntax-case
(lambda (x)
(syntax-case x ()
((guarded-syntax-case y (literal ...) clause ...)
#'(syntax-case y (literal ...) clause ...))))))
;; test case
(define-syntax (binop stx)
(guarded-syntax-case stx () ; *problem site*
[(_ op n1 n2) #'(op n1 n2)]))
(binop + 1 2) ;=> 3
Alternatively, you can define a (sub)module that provides guarded-syntax-case, and then require the (sub)module with for-syntax. Here's the full code:
#lang racket
(module lib racket
(provide guarded-syntax-case)
;; definition
(define-syntax guarded-syntax-case
(lambda (x)
(syntax-case x ()
((guarded-syntax-case y (literal ...) clause ...)
#'(syntax-case y (literal ...) clause ...))))))
(require (for-syntax 'lib))
;; test case
(define-syntax (binop stx)
(guarded-syntax-case stx () ; *problem site*
[(_ op n1 n2) #'(op n1 n2)]))
(binop + 1 2)

In Racket, can I redefine the form `if` and have other derived forms automatically follow its new semantics?

In a custom Racket language, I would like to change the behavior of the core form if as well as other forms that expand to it (such as and and cond).
Naturally, I could redefine each of these forms but this seems rather redundant. For instance, here is an example where the modified if expects each of its arguments to be wrapped in a list. The macro and is here redefined explicitly.
;; my-lang.rkt
#lang racket/base
(require (for-syntax racket/base))
(provide #%module-begin #%datum #%app
list
(rename-out [car-if if] [car-and and]))
(define-syntax (car-if stx)
(syntax-case stx ()
[(_ c t f) #'(if (car c) t f)]))
(define-syntax (car-and stx) ; this seems redundant
(syntax-case stx ()
[(_) #'#t]
[(_ x) #'x]
[(_ x xs ...) #'(car-if x (car-and xs ...) x)]))
#lang s-exp "my-lang.rkt"
(if (list #f) (list 2) (list 3)) ; => (3)
(and (list #f) (list 2)) ; => (#f)
Is there an easier way to redefine these forms by injecting my new definition of if into the existing definitions provided by racket/base?
The answer is no.
Let's consider the form and. It is defined as a macro (somewhere).
It looks something like:
#lang mumble
(define-syntax (and stx)
(syntax-case stx ()
[(_and) #'#t]
[(_and e) #'e]
[(_and e1 e2) #'(let ([t e1]) (if t e2 #f))]
[(_and e1 e2 e ...) #'(let ([t e1]) (if t (and e2 e ...)))]
[_ (raise-syntax-error 'and "bad syntax" stx)]))
Since the Racket macro system is "referentially transparent" the
identifiers are bound using standard lexical scope rules. That is
the if in the expansion is bound to the if in the module where
the macro is defined. The point is that the macro writer doesn't
need to fear any users redefining any identifiers used in the expansion.
The only way to change the behaviour of the and macro above is to
change the if used. So only if you have access to the definition
of "mumble", you can change the if used. In the case of the standard
Racket and no user can change the definitions.
In short, the answer is "no" due to the design of the macro system.

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.

racket: macro expand inside match pattern

Is there any way to detect if a macro is expanding inside a pattern match?
Here's an example macro that I'd like to write, but it fails inside a match-define:
#lang racket/base
(require racket/match (for-syntax racket/base syntax/parse))
(struct point (x y))
(define-syntax (friendly-point stx)
(syntax-parse stx
[(_ arg* ...)
#'(begin (printf "Now making a point\n") (point arg* ...))]
[_ #'(begin (printf "Hello point\n") point)]))
(define p (friendly-point 1 2))
;; Prints "Now making a point"
(match-define (friendly-point x y) p)
;; ERROR
Yes. Instead of using an ordinary syntax transformer created with define-syntax, use define-match-expander to create a macro that can cooperate with match.
(require (for-syntax syntax/parse))
(define-match-expander positive
(syntax-parser
[(_ n)
#'(? positive? n)]))
(match 3
[(positive n) (~a n " is positive")])
; => "3 is positive"
The define-match-expander form is flexible: it can be used to create macros that may only be used inside of match, but it can also be used to create macros that expand differently depending on how they are used by providing two transformer functions, one for each context. This allows you to have “context-sensitive” identifiers which work as both functions and as match expanders.
(require (for-syntax syntax/parse)
(prefix-in base: racket/base))
(define-match-expander syntax
(syntax-parser
[(_ x)
#'(? syntax? (app syntax->datum x))])
(make-rename-transformer #'base:syntax))
(match (syntax (1 2 3))
[(syntax n) (~a n " is a syntax list")])
If you need even more flexibility, you can forego define-match-expander entirely and define a custom struct with the prop:match-expander structure type property. This can be combined with prop:procedure to achieve the two-argument functionality described above, but it can also hold state, and it can be paired with other structure type properties such as prop:rename-transformer to allow the same identifier to function in many, many different contexts.
What you are looking for is define-match-expander. It allows you to make a macro that is expanded inside of a pattern matching context. (Also, because it takes in two thunks, you can have a variant that is also used when not in a matching context. Next, I should point out that
Next, you can have a printing side effect inside of the template of a define-match-expander, but you can have in the macro itself. (Note though that the side effect will not occur if your module has already been expanded. This is explain in more detail in this paper.
So, using match expanders, including a second function for use outside of match, you get the following code:
#lang racket/base
(require racket/match (for-syntax racket/base syntax/parse))
(struct point (x y))
(define-match-expander friendly-point
(lambda (stx)
(syntax-parse stx
[(_ arg* ...)
(printf "Now matching a point\n")
#'(point arg* ...)]
[_ #'point]))
(lambda (stx)
(syntax-parse stx
[(_ args* ...)
#'(begin (printf "Now making a point\n") (point args* ...))])))
(define p (friendly-point 1 2))
;; Prints "Now making a point"
(match-define (friendly-point x y) p)
;; Works fine now

How do you write an MIT Scheme macro to return a lambda form?

I'm baffled by trying to create the equivalent of this trivial (in Common Lisp) macro in MIT Scheme:
(defmacro funcify (exp)
`(lambda (x) ,exp))
This is for a simple personal project, a numerical equation solver based on the functions built in the second SICP lecture. I don't care that this macro is not "safe" or "hygienic" or will capture a variable if the exp references any symbols other than 'x. I'd like to be able to write
(solv '(* 60 x) '(* 90 (- x 1)))
where solv is:
(define (solv lh-exp rh-exp)
(solve (funcify lh-exp) (funcify rh-exp)))
instead of having to type
(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1))))
But can't figure out how to do this using MIT Scheme syntax-rules.
I've tried this but it doesn't work:
(define-syntax funcify
(syntax-rules ()
((funcify y) (lambda (x) y))))
;Value: funcify
(funcify x)
;Value 17: #[compound-procedure 17]
((funcify x) 10)
;Unbound variable: x
I've tried other things probably not worth mentioning involving eval but to no avail.
Also, references to good tutorials (not references) on Scheme's macro system that start with small simple examples and build up, with ample commentary, and in particular show how to convert backquote-comma style LISP macros (which to me are highly intuitive) to Scheme's syntax macro system would be great.
It cannot be done in syntax-rules. End of story.
Injecting an arbitrary identifier (x, in your case) into the output expression requires breaking hygiene, and syntax-rules does not provide any means to break hygiene. You will need to use a lower-level macro system to do this. MIT Scheme uses explicit renaming (see Matthias Benkard's answer), but for other Scheme implementations that use syntax-case, you can do it thus:
(define-syntax funcify
(lambda (stx)
(syntax-case stx ()
((_ body)
(with-syntax ((x (datum->syntax stx 'x)))
#'(lambda (x)
body))))))
The key is the (datum->syntax stx 'x) bit, which injects the symbol x as if it were in the syntactic context of the funcify invocation.
By the way, your solv must also be a macro, not a procedure, but at least it can be a syntax-rules macro:
(define-syntax solv
(syntax-rules ()
((_ lhs rhs) (solve (funcify lhs) (funcify rhs)))))
You can do basically the same thing as with defmacro by using explicit-renaming macros. The only significant difference is that you will have to destructure the input form yourself:
(define-syntax funcify
(er-macro-transformer
(lambda (form rename cmp)
(let ((exp (cadr form)))
`(,(rename 'lambda) (x) ,exp)))))