问题
I have one more questions about Hygienic macros in Scheme, consider example from R5RS
(let-syntax ((when (syntax-rules ()
((when test stmt1 stmt2 ...)
(if test
(begin stmt1
stmt2 ...))))))
(let ((if #t))
(when if (set! if 'now))
if))
Why it match if the pattern have 3 arguments and ellipsis that can match empty list?
It's called with 2 arguments if
and (set! if 'now)
. What should be ...
bind to, if stmt2
can be bind to empty list? This is kind of non Lispy if ... is just nothing. Is that true?
What should be the expansion of when in this context? What is the value of stmt2
?
Why this don't work but the first code does?
(let-syntax ((when (syntax-rules ()
((when test stmt1 stmt2 ...)
(if test
(begin stmt1
stmt2 ...))))))
(when if 10))
it work in Kawa but not in Guile, is that the bug in Guile and it should in fact work like in Kawa?
And one more question why it don't evaluate to nil
? If next element in list after 10
, is nil
so stmt2
should be nil
? R5RS is not very helpful in that regard.
I'm asking this because I've just finsihed renaming scheme for my macro system in LIPS Scheme and when I'm pattern matching I've got comparison of stmt2
and nil
and there is also ...
left. Should in this case ...
just be ignored and stmt2
should be nil
? And it should match even that there is one less symbol in pattern? This is really confusing.
What should be the expansion of last snippet of code?
EDIT:
One more thought
(let-syntax ((when (syntax-rules ()
((when test stmt1 . stmt2)
(if test
(begin stmt1
stmt2))))))
(when if 10))
This works in Kawa and return nil
as expected but in Guile it throw exception, I consider Kawa Scheme to be better in following spec.
But why it even match the pattern if there are not enough arguments?
回答1:
Yes. It is very non lispy that we have a modifier ...
that changes the meaning of element in front. eg. something ...
is basically similar to . something
except it works with structures like this:
(define-syntax my-let
(syntax-rules ()
((_ ((a b) ...)
body1 bodyn ...)
((lambda (a ...)
body1 bodyn ...)
b ...))))
Notice I use body1
ro require at least one expression in the body since bodyn ...
can be zero or more elements. This will turn:
(my-let ()
test)
==>
((lambda () test))
As well as
(my-let ((a b) (c d))
test1 test2)
==>
((lambda (a c)
test1 test2)
b
d)
My example cannot be rewritten with cons syntax, but basically using .
works the same way as rest arguments in the pattern and .
in a quote:
'(a b . (c d))
; ==> (a b c d)
Your when
would not work with more than one expression.
eg.
(let-syntax ((when (syntax-rules ()
((when test stmt1 . stmt2)
(if test
(begin stmt1
stmt2))))))
(define if #t)
(when if (display 'true) #t))
Imagine that all report bindings also exist under r5rs:
prefix. The expansion will become:
(r5rs:if if
(begin (display 'true)
(#t)))
; ERROR: Application not a procedure: #t
This is correct:
(let-syntax ((when (syntax-rules ()
((when test stmt1 . stmt2)
(if test
(begin stmt1
. stmt2))))))
(define if #t)
(when if (display 'true) #t))
; ==> #t (prints true)
来源:https://stackoverflow.com/questions/61195399/missing-argument-in-syntax-rules-hygienic-macro-call-from-scheme-r5rs-example