ashinn / chibi-scheme

Official chibi-scheme repository
Other
1.21k stars 142 forks source link

let-syntax cannot be used for macros that define values #895

Closed Zambito1 closed 1 year ago

Zambito1 commented 1 year ago

I believe this is a bug, but please let me know if I'm wrong.

let-syntax can be used to wrap syntax-rules expressions with local macros. For example, the following block:

(define-syntax bar
  (syntax-rules ()
    ((_ (key . value) ...)
     (+ 0 value ...))))

(define-syntax baz
  (syntax-rules ()
    ((_ (key . value) ...)
     (+ 0 key ...))))

(define-syntax foo
  (syntax-rules ()
    ((_ args ...)
     (* (bar args ...) (baz args ...)))))

Can be refactored like so, if we are not using bar or baz outside of foo:

(define-syntax foo
  (let-syntax ((bar
        (syntax-rules ()
          ((_ (key . value) ...)
           (+ 0 value ...))))
           (baz
        (syntax-rules ()
          ((_ (key . value) ...)
           (+ 0 key ...)))))
    (syntax-rules ()
      ((_ args ...)
       (* (bar args ...) (baz args ...))))))

And foo will still work the same way. However the following macros work:

(define-syntax bar
  (syntax-rules ()
    ((_ (name value))
     (define name value))))

(define-syntax foo
  (syntax-rules ()
    ((_ args ...)
     (begin
       (bar args) ...))))

(foo (a 5) (b (lambda (x) (+ x 1))))
(b a) ; returns 6 as expected

but using let-syntax to package bar internal to foo does not work:

(define-syntax foo
  (let-syntax ((bar
        (syntax-rules ()
          ((_ (name value))
           (define name value)))))
    (syntax-rules ()
      ((_ args ...)
       (begin
     (bar args) ...)))))

(foo (a 5) (b (lambda (x) (+ x 1))))

ERROR: undefined variable: a
Searching for modules exporting a ...
... none found.

It seems to me like any top level macro of the form:

(define-syntax bar ...)
(define-syntax foo
  (syntax-rules ()
    (<pattern> <usage of bar>)))

Should have an equivalent definition of foo:

(define-syntax foo
  (let-syntax ((bar ...))
    (syntax-rules ()
      (<pattern> <usage of bar>))))
mnieper commented 1 year ago

Code like

(define-syntax foo
  (let-syntax ...
    (syntax-rules () ...)))

is not valid R7RS(-small). A macro transformer must be of the form (syntax-rules () ...) and not some arbitrary expression.

Chibi extends it because it offers ER macro transformers (for which there is no formal specification), but the way it implements them, the definition of bar is only visible to the actual ER transformer (to which syntax-rules expands), so the identifier bar in the output does not resolve to the local syntax definition.

It would neither work in a Scheme with a syntax-case system because the identifier bar would be out of phase.

Zambito1 commented 1 year ago

I must have jumbled up things when I was entering them into my REPL. It turns out my second example

(define-syntax foo
  (let-syntax ((bar
        (syntax-rules ()
          ((_ (key . value) ...)
           (+ 0 value ...))))
           (baz
        (syntax-rules ()
          ((_ (key . value) ...)
           (+ 0 key ...)))))
    (syntax-rules ()
      ((_ args ...)
       (* (bar args ...) (baz args ...))))))

does not actually work. I thought that was working as I intended which threw me off. Thank you for the explanation.