首页 > 解决方案 > Scheme 的语法规则——在 `...` 中混合不同的语法选择

问题描述

假设我有一个宏(define/custom (name (arg type) ...) body ...)扩展为(define (name arg ...) body ...). 这很容易。

现在,我不仅要允许(arg type)作为参数传递,而且要简单地传递arg. 好的,所以我写了第二个子句,将 where(define/custom (name arg ...) body ...)扩展为(define (name arg ...) body ...). 也很容易。

但是有了这样的解决方案,要么所有参数都带有类型,要么都没有。我怎样才能允许在同一个语法列表(或任何...所谓的)中混合这两个选项?我该怎么做,例如。(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扩展之前。

标签: macrosschemesyntax-rules

解决方案


您可以使用辅助宏来执行此操作,该宏循环遍历每个“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+typehelper 处理的地方。

(define-syntax define/custom
  (syntax-rules ()
    ((_ (name arg-or-arg+type ...) body ...)
     (define/custom-helper (name () (arg-or-arg+type ...)) body ...))))

推荐阅读