【问题标题】:Recursive macro in scheme causes unexpected loop方案中的递归宏导致意外循环
【发布时间】:2018-04-03 14:11:31
【问题描述】:

有人能解释一下为什么这段代码会导致循环吗?

(define-macro proc
 (lambda (n)
   `(begin
     (display ,n)
     (set! ,n (+ ,n 1))
     (if (< ,n 10)
         (proc ,n)))))

(let ((x 5))
  (proc x))

【问题讨论】:

  • 连Scheme都没有,报告中找不到define-macro
  • 我的意思是,有几个方案“确实”支持define-macro,尽管它们通常(非常)不鼓励:gnu.org/software/guile/manual/html_node/Defmacros.html。 Racket 也有一个,尽管它也非常不鼓励:docs.racket-lang.org/compatibility/…
  • @LeifAndersen 我认为 bipll 暗示 define-macro 不在任何报告中,因此不是真正的方案形式。大多数实现都有宏,因为它是实现语言的唯一明智的方法,但这是事实上的。作为一个有效的比较:只知道在 PyPy 中工作的表单真的是 Python 代码吗?我投票赞成删除方案和 lisp 标签。
  • 我的意思是,根据这个论点,我们还应该删除 Racket 标签。因为那不是真正的球拍代码,也不是球拍生态系统的一部分(除了兼容性库)。此外,Python 的标准是(afaict)CPython 实现。所以不,它不会是python。 Scheme 并没有真正的单一规范标准。正如 2017 年计划研讨会所见,计划社区无法真正决定 RNRS 文档实际上应该是什么。
  • 一个阵营声称它是一个标准。但另一个人只是简单地声称它只是方案系统当前状态的一个描述符,大多数实现都试图使用它以使代码可移植性更容易。

标签: scheme lisp racket


【解决方案1】:

You proc总是 扩展为对 proc 的调用。如果你想有条件地扩展,你的测试必须在宏扩展时完成(未测试):

(define-macro proc 
  (lambda (n) 
    `(begin ,(if (< n 10) `(proc ,(+ n 1)) '())))

【讨论】:

  • 这将要求 N 的值在时间宏扩展时是已知的......
【解决方案2】:

您永远不会停止宏扩展 - 宏扩展发生在评估之前而不是“按需”,因此您不能将评估时间值用于条件扩展。

换句话说,

(proc x)

扩展到

(begin
 (display x)
 (set! x (+ x 1))
 (if (< x 10)
     (proc x)))

扩展为

(begin
 (display x)
 (set! x (+ x 1))
 (if (< x 10)
     (begin
         (display x)
         (set! x (+ x 1))
         (if (< x 10)
             (proc x)))))

扩展为

(begin
 (display x)
 (set! x (+ x 1))
 (if (< x 10)
     (begin
         (display x)
         (set! x (+ x 1))
         (if (< x 10)
             (begin
                 (display x)
                 (set! x (+ x 1))
                 (if (< x 10)
                 (proc x)))))))

以此类推,无穷无尽。

【讨论】:

    猜你喜欢
    • 2019-12-05
    • 2017-03-03
    • 2011-04-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    相关资源
    最近更新 更多