macros - 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
扩展之前。
解决方案
您可以使用辅助宏来执行此操作,该宏循环遍历每个“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 ...))))
推荐阅读
- xquery - 如何使用 cts:values/cts:element-attribute-values 过滤条件
- sql - 如何从 PL/SQL 查询(使用 dbms_output)返回值到 JMeters 查看结果树?
- angular - 在 http.get 中获取大数据 (>256 MB)
- excel - 使用初始名称创建单词
- javascript - Unlayer EmailEditor 导入 React 中断应用程序
- sql - 从日期时间 SQL 中提取时间
- elixir - 从另一个 GenServer 调用 GenServer
- c# - WPF ComboBox 选定项到字符串
- r - Dplyr 和 Tidyverse => 有条件地替换所有变量(循环数据集)
- java - For 循环很慢 - Java