2

注意:这似乎是 Gauche Scheme 版本 0.9.3.3。
我似乎无法理解这些 Lisp 语言:/。

我正在尝试在 Scheme 中定义一个 for 循环语法。我不确定这是否可以通过递归函数实现(我认为可以),但此时我真的很想开始define-syntax工作。

我可以使用以下代码让循环运行一次(然后看起来它终止了):

(define-syntax forloop
  (syntax-rules ()
    ((forloop start stop exps)
      (letrec ((aloop (lambda (astart astop aexps)
        (if (<= astart astop) (begin aexps (aloop (+ astart 1) astop aexps))))))
          (aloop start stop exps)))))

也可以用省略号定义它会很好,但这会给出“模板包含常量形式的重复”。我已经阅读了 R5RS 规范的宏部分,不过我很快会重新阅读模板部分:

(define-syntax forloop
  (syntax-rules ()
    ((forloop start stop exps ...)
      (letrec ((aloop (lambda (astart astop aexps ...)
        (if (<= astart astop) (begin aexps ... (aloop (+ astart 1) astop aexps ...))))))
        (aloop start stop exps ...)))))

我首先尝试了这个,但它运行了大约 10 秒,然后没有任何输出就失败了......我正在使用compileonline.com,所以这可能与它有关:

(define-syntax forloop
  (syntax-rules ()
    ((forloop start stop exps ...) 
      (if (<= start stop) 
        (begin exps ... (forloop (+ start 1) stop exps ...))))))

如果我从不调用 forloop 就没有问题(我认为这是因为它永远不必扩展宏),所以我用来测试这些的代码是:

(forloop 6 8 (display "g"))

我究竟做错了什么?我已经成功地实现了一个when声明(我自己,但那里有几十个例子,我已经看过很多)。我认为我想做的事情的递归性质和省略号把我搞砸了。

4

1 回答 1

2

宏在编译时被扩展,因此类似的东西(begin exps ... (forloop (+ start 1) stop exps ...))forloop一次又一次地扩展,不管它的值(+ start 1)是什么(在运行时评估)。

也许你能做的最好的事情,至少syntax-rules是使用宏来捕获要运行的表达式,并使用非宏代码来处理循环:

(define-syntax forloop
  (syntax-rules ()
    ((forloop start stop exps ...)
     (let ((j stop))
       (let loop ((i start))
         (when (<= i j)
           exps ...
           (loop (+ i 1))))))))

您还可以使用do循环:

(define-syntax forloop
  (syntax-rules ()
    ((forloop start stop exps ...)
     (let ((j stop))
       (do ((i start (+ i 1)))
           ((> i j))
         exps ...)))))
于 2013-12-28T04:11:58.660 回答