我想写一种新的球拍语言,以某种特殊的方式捕捉和处理字符串 . 我编写了以下示例代码:
#lang racket
(provide #%top #%app #%top-interaction #%module-begin
(rename-out [datum #%datum]))
(define big-string "")
(define (add-string x)
(set! big-string (string-append big-string x)))
(define-syntax (datum stx)
(syntax-case stx ()
[(_ . x)
#'(if (string? x)
(#%datum . (add-string x))
(#%datum . x))]))
当我尝试使用目标语言时,它会给我一个内存不足的错误 . 是递归调用自己吗?我原以为卫生会阻止这种情况发生 .
也许问题是#%datum返回语法而不是基准?
1 回答
首先让's look at the problem with version of datum above. Let'说该程序包含字符串
"a"
. 扩展器看到字符串"a"
并将其转换为(#%datum . "a")
. 由于#%datum
必须datum
定义为:语法
(#%datum . "a")
将扩展为然后扩展器将开始扩展上面的表达式 . 当涉及到第一个
"a"
时,它会将其扩展为(#%datum . "a")
,这将成为(datum . "a")
,然后成为另一个副本等等
datum
的意图是使用两个不同的扩展(add-string x)
或(#%datum . x)
. 但是,由于datum
的输出是#'(if (string? x) ...)
,if
不会在编译时评估,而是在运行时评估 .解决方案是移动
if
.除了移动
if
我改变了add-string
后果 .注意:如果宏使用扩展为使用相同的宏,那么您可能会遇到这种无限扩展问题 . 找到罪魁祸首的最简单方法是使用宏步进器 . 将“宏隐藏:”设置转为“禁用” . 然后一步一步,直到看到循环 .