Missing argument in syntax-rules Hygienic macro call from Scheme R5RS example

此生再无相见时 提交于 2021-02-11 16:59:50

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!