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 ...))))