Reputation: 567
Recently I read one blog implementing amb
with macro transformer. It has 2 implementations.
(define-syntax amb
(syntax-rules ()
((_) (fail))
((_ a) a)
((_ a b ...)
(let ((fail0 fail))
(call/cc
(lambda (cc)
(set! fail
(lambda ()
(set! fail fail0)
(cc (amb b ...))))
(cc a)))))))
; for MIT-Scheme only
; use it if you don't like warning during compilation
(define-syntax amb
(sc-macro-transformer
(lambda (exp env)
(if (null? (cdr exp))
`(fail)
`(let ((fail0 fail))
(call/cc
(lambda (cc)
(set! fail
(lambda ()
(set! fail fail0)
(cc (amb ,@(map (lambda (x)
(make-syntactic-closure env '() x))
(cddr exp))))))
(cc ,(make-syntactic-closure env '() (second exp))))))))))
I can't understand "use it if you don't like warning during compilation".
I only know the possible compilation error caused by syntax-rules
for some Scheme implementation said by this syntax-rules
detailed unofficial doc
(define-syntax please (syntax-rules () ((please . forms) forms)))
... subforms that are introduced by the template continue to refer to the lexical environment of the macro definition. The list that is returned from the PLEASE macro, however, is a subform that was not created at either the macro use point or at the macro definition point, but rather in the environment of the pattern matcher. ... The fix is trivial:
(define-syntax please (syntax-rules () ((please function . arguments) (function . arguments))))
The resulting expansion is now a list constructed within the template of the macro
Here "the macro use point" may mean the case where the recursive structure is used, so partial expansion is also done while using the macro.
The structure of them are almost same except that Pattern Language replace a b ...
with the pattern like foo bar
in (amb foo bar)
while syntactic-closures macro transformer uses syntactic closure.
A syntactic closure consists of a form, a syntactic environment, and a list of identifiers. All identifiers in the form take their meaning from the syntactic environment, except those in the given list. The identifiers in the list are to have their meanings determined later.
IMHO syntactic closure is very similar to procedure in Scheme except that it has one free-names
argument when construction make-syntactic-closure environment free-names form
(see MIT/GNU Scheme doc) which means these variable are not local in environment
.
The environment
is normally passed by sc-macro-transformer
. MIT/GNU Scheme doc says
The second argument, the usage environment, is the syntactic environment in which the input form occurred.
That is very similar to continuation except that continuation is one procedure instead of one env variable.
Since sc-macro-transformer
gives one fine-grained control for env, I thought about ont situation where sc-macro-transformer
can achieve the excepted behavior while syntax-rules
can't hinted by this QA.
(define-syntax aif
(sc-macro-transformer
(lambda (exp env)
(let ((test (make-syntactic-closure env '(it) (second exp)))
(cthen (make-syntactic-closure env '() (third exp)))
(celse (if (pair? (cdddr exp))
(make-syntactic-closure env '(it) (fourth exp))
#f)))
`(let ((it ,test))
(if it ,cthen ,celse))))))
(let ((i 4)
(it (cons 1 2)))
(aif (memv i '(2 4 6 8))
(car it)))
;; captured by the output form, i.e. that created by let in the transformer.
; 4
;; here we need no extra literal
(define-syntax aif
(syntax-rules ()
((aif test cthen)
(let ((it test))
(if it cthen #f)))
((aif test cthen celse)
(let ((it test))
(if it cthen celse)))))
(let ((i 4)
(it (cons 1 2)))
(aif (memv i '(2 4 6 8))
(car it)))
;; it in the caller has no connection with it in the template. Also see "loop" context in https://stackoverflow.com/q/79098453/21294350
; 1
;; won'e be expanded as since MIT/GNU Scheme will differentiate it's at different locations appropriately as the above comment says.
(let ((i 4)
(it (cons 1 2)))
(let ((it (memv i '(2 4 6 8))))
(if it (car it) #f)))
; 4
But this seems to have no relation with "warning during compilation".
Q:
What does the above "warning during compilation" mean for syntax-rules
? That doesn't exist for MIT/GNU Scheme 12.1 at least when I used that amb implementation, maybe it exists for other Scheme implementations.
If that is not one cause for using sc-macro-transformer
instead of syntax-rules
, then when should we use sc-macro-transformer in MIT/GNU Scheme except for the above situation to have fine-grained control of env by free-names
?
Later I found one really helpful guile doc incidentally (I say this because I originally tried to search the old define-macro
syntax usage which is shown many times in the old MIT 6.001 lec/rec's) saying how to use syntax-case
to implement aif
done by
introduce a piece of the lexical environment into the pattern variable environment
which does the similar thing to the above free-names
.
So the previous section there showing comparison between syntax-rules
and syntax-case
also works for comparison between syntax-rules
and sc-macro-transformer
.
Also later when track the Up link for MIT/GNU Scheme doc, I found
A standard high-level pattern language for specifying macro transformers, introduced by the syntax-rules special form.
Two non-standard low-level languages for specifying macro transformers, syntactic closures and explicit renaming.
So the problem seems to ask something like when should we use assembly language which can only be answered well with one specific context, like one detailed OS kernel function definition. But that is one really weird question at all when currently most of people uses high level programming languages since that is more appropriate for the work requirements.
So this question may be better to closed now. I didn't delete this question since I found few questions about sc-macro-transformer
in Stack Overflow, then this may probably help some newbie like me in the future.
Upvotes: 0
Views: 73