Defining defmacro in terms of define-syntax

27 views
Skip to first unread message

Martin Ward

unread,
Jun 28, 2025, 12:25:36 PMJun 28
to chez-scheme

I need a way to define defmacro in Chez Scheme
(which only has syntax-rules and syntax-case).

I found a definition for chicken that uses er-macro-transformer

(define-syntax defmacro
  (syntax-rules ()
    ((_ ?name ?args ?body ...)
     (define-syntax ?name
       (er-macro-transformer
         (lambda (e r c)
           (apply (lambda ?args ?body ...) (cdr e))))))))

But Chez does not have er-macro-transformer

bigloo has define-macro, so it is easy:

  (define-macro (defmacro name . forms)
    \`(define-macro (,name . ,(car forms)) ,\@(cdr forms)))

But Chez does not have define macro.

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

-- 
            Martin

Dr Martin Ward | Email: mar...@gkc.org.uk | http://www.gkc.org.uk
G.K.Chesterton site: http://www.gkc.org.uk/gkc | Erdos number: 4

Marc Nieper-Wißkirchen

unread,
Jun 28, 2025, 12:32:07 PMJun 28
to chez-scheme
Why do you need `defmacro`?

In any case, the answer to your question can be found in Section 12.6 of the R6RS Standard Libraries report; see `lisp-transformer`. You use it instead of `syntax-rules`.

Best,

Marc

Philip McGrath

unread,
Jun 28, 2025, 1:23:27 PMJun 28
to chez-scheme
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)))])))]))))
```

Martin Ward

unread,
Jun 28, 2025, 1:44:15 PMJun 28
to chez-scheme
This is great, thanks very much for your help!
Reply all
Reply to author
Forward
0 new messages