首页 文章

如何编写新的#%基准函数来捕获所有字符串?

提问于
浏览
4

我想写一种新的球拍语言,以某种特殊的方式捕捉和处理字符串 . 我编写了以下示例代码:

#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 回答

  • 2

    首先让's look at the problem with version of datum above. Let'说该程序包含字符串 "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 的意图是使用两个不同的扩展 (add-string 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 我改变了 add-string 后果 .

    注意:如果宏使用扩展为使用相同的宏,那么您可能会遇到这种无限扩展问题 . 找到罪魁祸首的最简单方法是使用宏步进器 . 将“宏隐藏:”设置转为“禁用” . 然后一步一步,直到看到循环 .

相关问题