A very beginning macro question: (define-syntax switch-log
(syntax-rules ()
[(_ #t)
(begin
(define (printf/debug x . xs) (apply printf (cons x xs)))
(define (printf/info x . xs) (apply printf (cons x xs)))
(define (printf/warning x . xs) (apply printf (cons x xs))))]
[(_ #f)
(begin
(define (printf/debug x . xs) (void))
(define (printf/info x . xs) (void))
(define (printf/warning x . xs) (void)))]))
(switch-log #t)
(printf/debug "xxx") ; <--- ERROR: printf/debug: unbound identifier
But (switch-log #t)
exactly macro expand to (begin
(define-values
(printf/debug)
(lambda (x . xs) (#%app apply printf (#%app cons x xs))))
(define-values
(printf/info)
(lambda (x . xs) (#%app apply printf (#%app cons x xs))))
(define-values
(printf/warning)
(lambda (x . xs) (#%app apply printf (#%app cons x xs)))))
(printf/debug "xxx")
;; xxx
Need help, thanks.
Possibly a scoping/hygiene thing? That is, the scope information attached to the syntax-objects for the ids printf/debug
(etc.) may not include the right scope? I’m not sure of that, though
@chansey97 With syntax-rules
you need to do this: (define-syntax switch-log
(syntax-rules ()
[(_ printf/debug printf/info printf/warning #t)
(begin
(define (printf/debug x . xs) (apply printf (cons x xs)))
(define (printf/info x . xs) (apply printf (cons x xs)))
(define (printf/warning x . xs) (apply printf (cons x xs))))]
[(_ printf/debug printf/info printf/warning #f)
(begin
(define (printf/debug x . xs) (void))
(define (printf/info x . xs) (void))
(define (printf/warning x . xs) (void)))]))
(switch-log printf/debug printf/info printf/warning #t)
(printf/debug "xxx")
Time to try out syntax-parse
!
Thanks all! (Although I don’t know exactly what’s going on inside.)
The problem is that syntax-rules
can’t introduce new identifiers where the macro is used (at the place where you write (switch-log #t)
. The solution is to give the identifiers to syntax-rules
.
The default scope for a an identifier that appears in a template is restricted to referenced to it in that template.
Can I understand that syntax-rules
can capture identifiers, but can not create identifiers?
I am not sure what you mean by “capture an identifier”.
(define printf/debug #f)
(define printf/info #f)
(define printf/warning #f)
(define-syntax switch-log
(syntax-rules ()
[(_ #t)
(begin
(set! printf/debug (lambda (x . xs) (apply printf (cons x xs))))
(set! printf/info (lambda (x . xs) (apply printf (cons x xs))))
(set! printf/warning (lambda (x . xs) (apply printf (cons x xs)))))]
[(_ #f)
(begin
(set! printf/debug (lambda (x . xs) (void)))
(set! printf/info (lambda (x . xs) (void)))
(set! printf/warning (lambda (x . xs) (void))))]))
(switch-log #t)
(printf/debug "xxx")
;; xxx
Then OK.
This is fine due to lexical scope.
Yes. In this case, syntax-rules captured printf/debug. But if no printf/debug
identifier in advance, syntax-rules can not create by define, unless manually pass them.
Yes.
The syntax-case
and syntax-parse
macro systems use format-id
or datum->syntax
to transfer the context of call to a new identifier. That is, they can make an identifier that behaves as it had been passed to the macro (as in the version I wrote above).
I accidentally found that struct constructor does not support keywords.