Hi,
On Sat, Jun 28, 2025, at 12:25 PM, Martin Ward wrote:
>
> I need a way to define defmacro in Chez Scheme
> (which only has syntax-rules and syntax-case).
>
> ...
>
> I found this definition on an old mailing list
>
https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg01105.html
>
> (define-syntax defmacro
> (lambda (so)
> (datum->syntax-object so
> (let ((so-d (syntax-object->datum so)))
> `(define-syntax ,(cadr so-d)
> (let ((xmfr (lambda ,@(cddr so-d))))
> (lambda (so)
> (datum->syntax-object so
> (apply xmfr
> (cdr (syntax-object->datum so)))))))))))
>
> but when I test it with:
>
> (defmacro pritt ()
> `(display "Hello from pritt!\n"))
>
> I get:
>
> Exception in datum->syntax-object: #<syntax (defmacro pritt () (quasiquote (...)))> is not an identifier
From context, it looks like that old mailing list discussion was using MzScheme (now a part of Racket), which can put "contextual information" on arbitrary syntax objects. In contrast, R6RS allows implementations that only track "contextual information" on identifiers. Thus, the R6RS `datum->syntax` requires its first argument to be an identifier, as the error message says, whereas MzScheme's `datum->syntax-object` (and Racket's `datum->syntax`) allow any syntax object. Chez Scheme provides `datum->syntax-object` as an alias for the R6RS `datum->syntax`,
This is documented in the section of R6RS that Marc mentioned:
https://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_sec_12.6
While the `lisp-transformer` example there is the essence of breaking hygiene, it is not quite a definition of `defmacro`. I've included a short implementation below (not thoroughly tested).
There is a more robust implementation in Racket's `compatibility/defmacro` library, which features better error checking and a "heuristic substitution [that] preserves source location information in many cases, despite the macro procedure’s operation on raw S-expressions". See the documentation (<
https://docs.racket-lang.org/compatibility/defmacro.html>) and implementation (<
https://github.com/racket/compatibility/blob/master/compatibility-lib/compatibility/defmacro.rkt>).
```scheme
#!r6rs
;; SPDX-License-Identifier: CC0-1.0
(library (defmacro)
(export defmacro)
(import (for (rnrs base) run expand)
(for (rnrs syntax-case) expand))
(define-syntax defmacro
(lambda (stx)
(syntax-case stx ()
[(_ name args body0 body ...)
(identifier? #'name)
#`(define-syntax name
(lambda (stx)
(syntax-case stx ()
[(name-in-use . rest-of-use)
(datum->syntax #'name-in-use
(apply (lambda args
body0 body ...)
(syntax->datum #'rest-of-use)))])))]))))
```