I'm running Chez Scheme 9.5 and am trying to define a syntax transformer in a library. Here's an example:
(library (forlib)
(export for)
(import (rnrs (6)))
(define-syntax for
(syntax-rules (in)
[(for x in lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
I save this in a file forlib.ss
and run chez
from the same directory.
Then in the REPL, I get this:
> (import (forlib))
> (for x in '(1 2 3) (display x))
Exception: invalid syntax (for x in (quote (1 2 3)) (display x))
Type (debug) to enter the debugger.
If I change the syntax definition to
(define-syntax for
(syntax-rules ()
[(for x lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
(without the in
keyword), everything works:
> (import (forlib))
> (for x '(1 2 3) (display x))
123
> _
Back to the old definition with the in
keyword.
If I put the test code into a test file:
;;; test-for.ss
(import (rnrs (6))
(forlib))
(for x in '(1 2 3) (display x))
and try to execute this file, the result depends on how I execute the file.
If I run this program using chez --program
, it works as expected:
$ chez --program test-for.ss
123
$ _
If I run it using chez --script
, I get the same error as above:
$ chez --script test-for.ss
Exception: invalid syntax (for x in (quote (1 2 3)) (display x)) at line 6, char 1 of test-for.ss
$ _
This raises two questions:
--script
fine with importing syntax forms without
special keywords but refuses to accept syntax forms that do have special
keywords in them?--script
and --program
? The
user manual says that --program
means that the file content is interpreted
as an rnrs top-level program but is silent as to what the semantics of
--script
are.Finally, to make my consfusion complete, if I enter the above syntax definition directly in the REPL, then everything works as expected:
> (define-syntax for
(syntax-rules (in)
[(for x in lst body1 body2 ...)
(for-each (lambda (x) body1 body2 ...) lst)])))
> (for x in '(1 2 3) (display x))
123
> _
So what is different in the REPL between syntax transformers imported from a library and syntax transformers defined directly in the REPL?
In Chez Scheme, some semantics differ between modes of operation. I'm going to name these modes r6rs and repl.
R6RS:
REPL:
For your specific question, you need to define and export an identifier named in
from forlib
if you want the repl and scripts to match the behavior of libraries and programs. This can be as simple as an empty define, or you can make a syntactic definition that throws an error when used outside of the macro body.
Simple:
(library (forlib)
(export for in)
(import (rnrs))
(define in)
(define-syntax for ...)
)
Syntactic Definition:
(library (forlib)
(export for in)
(import (rnrs))
(define-syntax in
(identifier-syntax
(error #f "Misplaced aux syntax in")))
(define-syntax for ...)
)
Both work fine; use whichever you prefer.
The other differences between repl and r6rs modes - that I know of - stem from how they evaluate expressions. In repl mode, each expression is handled on its own. That is to say, Chez reads an expression, evaluates said expression, and possibly prints the results. In r6rs mode, the entire contents of the file are evaluated as a single unit. Stated explicitly, the top-level continuation of repl mode is "read, eval, maybe print, and loop" while the top-level continuation of r6rs mode is the next expression. For example, this code will behave differently between running as a program or a script:
(import (chezscheme))
(define println)
(printf "~x\n"
(call/cc (lambda (k)
(set! println k)
1)))
(println 5)
(println 6)
Another difference is that in r6rs mode you cannot define a function and then use it in a syntax-case macro expansion outside of the syntax-quote.
(define ($two) 2)
(define-syntax two
(lambda (x)
(syntax-case x ()
[_ ($two)])))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With