Racket 如何编写新的#%datum函数来捕获所有字符串?
我想写一种新的球拍语言,它以某种特殊的方式捕捉和处理字符串。我编写了以下示例代码:Racket 如何编写新的#%datum函数来捕获所有字符串?,racket,Racket,我想写一种新的球拍语言,它以某种特殊的方式捕捉和处理字符串。我编写了以下示例代码: #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))) (d
#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返回语法,而不是datums?首先,让我们看看上述datum版本的问题。 假设程序包含字符串
“a”
。
扩展器看到字符串“a”
,并将其转换为(#%datum.a”)
。
由于#%datum
绑定到datum
定义为:
(define-syntax (datum stx)
(syntax-case stx ()
[(_ . x)
#'(if (string? x)
(#%datum . (add-string x))
(#%datum . x))]))
语法(#%datum.a”)
将扩展为
(if (string? "a")
(#%datum . (add-string "a"))
(#%datum . "a"))
然后,扩展器将开始展开上述表达式。
当涉及到第一个“a”
时,它会将其展开为(#%datum.a”)
成为(datum.a”)
,然后成为
(if (string? "a")
(#%datum . (add-string "a"))
(#%datum . "a"))
等等
datum
的目的是使用两种不同的扩展名,即(添加字符串x)
或(#%datum.x)
。但是,由于datum
的输出是#'(if(string?x)
因此if
不是在编译时计算的,而是在运行时计算的
解决方案是移动if
#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))
x)
(define-syntax (datum stx)
(syntax-case stx ()
[(_ . x)
(if (string? (syntax-e #'x))
#'(add-string (#%datum . x))
#'(#%datum . x))]))
除了移动if
外,我还更改了添加字符串的结果
注意:如果宏的使用扩展为同一宏的使用,
那么你很可能会遇到这个无限扩张的问题。
找到罪魁祸首的最简单方法是使用宏步进器。
将“宏隐藏:”设置改为“禁用”。然后一直走到你
查看循环。看起来像是添加字符串
需要有x
,因为它是最后一个表单,可以让表单计算为#
以外的内容。感谢您的全面回答。