Here is a very simple Scheme macro that works, running on MIT/GNU Scheme 12.1:
1 ]=> (define-syntax example
(syntax-rules ()
((_) 'ok)))
;Value: example
1 ]=> (example)
;Value: ok
However, defining the same macro with the name if
gives an error:
1 ]=> (define-syntax if
(syntax-rules ()
((_) 'ok)))
;Premature reference to reserved name: if
;To continue, call RESTART with an option number:
; (RESTART 1) => Return to read-eval-print level 1.
I've never used Scheme macros before, but I was under the impression that Scheme doesn't have "reserved" names and that any name in Scheme could be redefined. In fact, redefining if
to a normal procedure works as expected:
1 ]=> (define (if) 'ok)
;Value: if
1 ]=> (if)
;Value: ok
I skimmed through the section on macros in the reference manual (https://www.gnu.org/software/mit-scheme/documentation/stable/mit-scheme-ref/Macros.html), but I couldn't find the cause of the problem.
Is there something about the internal operation of syntax-rules
that is causing this to fail?
UPDATE 1
Locally redefining if
using let-syntax
works:
1 ]=> (let-syntax ((if (syntax-rules () ((_) 'ok))))
(if))
;Value: ok
I'm still not sure why define-syntax
doesn't work.
UPDATE 2
It is possible to shadow other built-in keywords with macros:
1 ]=> (define-syntax define (syntax-rules () ((_) 'ok)))
;Value: define
1 ]=> (define)
;Value: ok
1 ]=> (define-syntax set! (syntax-rules () ((_) 'ok)))
;Value: set!
1 ]=> (set!)
;Value: ok
1 ]=> (define-syntax lambda (syntax-rules () ((_) 'ok)))
;Value: lambda
1 ]=> (lambda)
;Value: ok
1 ]=> (define-syntax cond (syntax-rules () ((_) 'ok)))
;Value: cond
1 ]=> (cond)
;Value: ok
Hilariously, you can even redefine define-syntax
:
1 ]=> (define-syntax define-syntax (syntax-rules () ((_) 'ok)))
;Value: define-syntax
1 ]=> (define-syntax)
;Value: ok
However, attempting to redefine the keyword syntax-rules
gets a similar error as for redefining if
(note: I started a new REPL because the last macro shadowed define-syntax
):
1 ]=> (define-syntax syntax-rules (syntax-rules () ((_) 'ok)))
;Premature reference to reserved name: syntax-rules
;To continue, call RESTART with an option number:
; (RESTART 1) => Return to read-eval-print level 1.
if
can be defined as a macro at the toplevel in many Scheme implementations. I tested
(define-syntax if
(syntax-rules ()
((_) 'ok)))
(if) ; returns 'ok
on Guile 3.0.9, Chicken 5.3.0, Gauche 0.9.9, Chibi 0.10.0 (in the form of the latest from git), Chez 9.6.2, Gambit 4.9.5, Kawa 3.1.1, and MIT/GNU Scheme 11.2. All accepted and ran the code without errors. You said you're using MIT/GNU Scheme 12.1, so something that changed between the two versions is responsible.
Interestingly, the redefinition of syntax-rules
gives the error in 11.2. Guile, Chicken, Gauche, Chibi, and Gambit all accepted it, while Chez and Kawa threw errors.