Scheme 的语法规则——在 `...` 中混合不同的语法选择
Scheme's syntax-rules -- intermixing different syntax choices in `...`
假设我有一个宏 (define/custom (name (arg type) ...) body ...)
,除其他外,它扩展为 (define (name arg ...) body ...)
。很简单。
现在,我不仅要允许 (arg type)
作为参数传递,还要允许 arg
作为参数传递。好的,所以我写了第二个子句,其中 (define/custom (name arg ...) body ...)
扩展为 (define (name arg ...) body ...)
。也很简单。
但是对于这样的解决方案,要么所有参数都带有类型,要么其中 none 个是。我如何允许在同一语法列表中混合使用这两个选项(或调用 ...
的任何内容)?我怎样才能使,例如。 (define/custom (name arg1 (arg2 type2)) #f)
是否适当扩展为 (define (name arg1 arg2) #f)
?直觉是使用辅助宏,它将 (helper a)
扩展为 a
,将 (helper (a b))
扩展为 a
,并使 (define/custom (name arg_or_arg+type ...) body ...)
扩展为 (define (name (helper arg_or_arg+type) ...) body ...)
,但正如您可能知道并猜到的那样,这是行不通的,因为 define
扩展发生在 helper
扩展之前。
您可以使用辅助宏来执行此操作,该宏循环遍历每个“arg-or-arg+type”并将它们转换为 (arg type)
以保持一致。
首先,我建议定义一个仅适用于一致 (arg type)
版本的宏的核心版本:
(define-syntax define/custom-core
(syntax-rules ()
((_ (name (arg type) ...) body ...)
; among other things
(define (name arg ...) body ...))))
然后您可以定义处理 2 个输入参数列表的辅助宏:一个用于一致的 (arg type)
事物,另一个用于“arg-or-arg+type”事物。用法示例可能如下所示:
(define/custom-helper (name ((arg type) ...) (arg-or-arg+type ...)) body ...)
当它循环遍历 arg-or-arg+type ...
时,它将把它们移到 (arg type) ...
列表中。当 arg-or-arg+type ...
为空时,它就完成了,并将所有 (arg type)
的东西放入对 define/custom-core
.
的调用中
(define-syntax define/custom-helper
(syntax-rules ()
((_ (name (arg+type ...) ()) body ...)
(define/custom-core (name arg+type ...) body ...))
((_ (name (arg+type ...) ((arg type) . rest)) body ...)
(define/custom-helper (name (arg+type ... (arg type)) rest) body ...))
((_ (name (arg+type ...) (arg . rest)) body ...)
(define/custom-helper (name (arg+type ... (arg any)) rest) body ...))))
这依赖于 arg
等同于 (arg any)
。
那么,就剩下向外的define/custom
宏调用辅助宏了。它可以传递一个空的 arg+type
列表,并将 args 传递到 arg-or-arg+type
地方以供 helper 处理。
(define-syntax define/custom
(syntax-rules ()
((_ (name arg-or-arg+type ...) body ...)
(define/custom-helper (name () (arg-or-arg+type ...)) body ...))))
假设我有一个宏 (define/custom (name (arg type) ...) body ...)
,除其他外,它扩展为 (define (name arg ...) body ...)
。很简单。
现在,我不仅要允许 (arg type)
作为参数传递,还要允许 arg
作为参数传递。好的,所以我写了第二个子句,其中 (define/custom (name arg ...) body ...)
扩展为 (define (name arg ...) body ...)
。也很简单。
但是对于这样的解决方案,要么所有参数都带有类型,要么其中 none 个是。我如何允许在同一语法列表中混合使用这两个选项(或调用 ...
的任何内容)?我怎样才能使,例如。 (define/custom (name arg1 (arg2 type2)) #f)
是否适当扩展为 (define (name arg1 arg2) #f)
?直觉是使用辅助宏,它将 (helper a)
扩展为 a
,将 (helper (a b))
扩展为 a
,并使 (define/custom (name arg_or_arg+type ...) body ...)
扩展为 (define (name (helper arg_or_arg+type) ...) body ...)
,但正如您可能知道并猜到的那样,这是行不通的,因为 define
扩展发生在 helper
扩展之前。
您可以使用辅助宏来执行此操作,该宏循环遍历每个“arg-or-arg+type”并将它们转换为 (arg type)
以保持一致。
首先,我建议定义一个仅适用于一致 (arg type)
版本的宏的核心版本:
(define-syntax define/custom-core
(syntax-rules ()
((_ (name (arg type) ...) body ...)
; among other things
(define (name arg ...) body ...))))
然后您可以定义处理 2 个输入参数列表的辅助宏:一个用于一致的 (arg type)
事物,另一个用于“arg-or-arg+type”事物。用法示例可能如下所示:
(define/custom-helper (name ((arg type) ...) (arg-or-arg+type ...)) body ...)
当它循环遍历 arg-or-arg+type ...
时,它将把它们移到 (arg type) ...
列表中。当 arg-or-arg+type ...
为空时,它就完成了,并将所有 (arg type)
的东西放入对 define/custom-core
.
(define-syntax define/custom-helper
(syntax-rules ()
((_ (name (arg+type ...) ()) body ...)
(define/custom-core (name arg+type ...) body ...))
((_ (name (arg+type ...) ((arg type) . rest)) body ...)
(define/custom-helper (name (arg+type ... (arg type)) rest) body ...))
((_ (name (arg+type ...) (arg . rest)) body ...)
(define/custom-helper (name (arg+type ... (arg any)) rest) body ...))))
这依赖于 arg
等同于 (arg any)
。
那么,就剩下向外的define/custom
宏调用辅助宏了。它可以传递一个空的 arg+type
列表,并将 args 传递到 arg-or-arg+type
地方以供 helper 处理。
(define-syntax define/custom
(syntax-rules ()
((_ (name arg-or-arg+type ...) body ...)
(define/custom-helper (name () (arg-or-arg+type ...)) body ...))))