使用" define-syntax-rule"制作我自己的while循环

时间:2017-02-26 22:34:12

标签: while-loop scheme lisp racket define-syntax

我正在尝试使用" define-syntax-rule"在球拍中创建我自己的while循环。 我希望它是基于程序的,所以没有辅助函数(即只使用lambda,let,letrec等)。

我有这个,但它给了我某种lambda标识符错误。

(define-syntax-rule (while condition body)
  (lambda (iterate)
    (lambda (condition body) ( (if condition)
                                   body
                                   iterate))))

我希望它能够像普通的while循环一样使用它 例如:

(while (x < 10) (+ x 1))

调用它将(应该)在循环完成后返回10。

我的代码如何修复才能执行此操作?

2 个答案:

答案 0 :(得分:2)

以下是Standard Prelude中的while及其使用示例:

Petite Chez Scheme Version 8.4
Copyright (c) 1985-2011 Cadence Research Systems

> (define-syntax while
    (syntax-rules ()
      ((while pred? body ...)
        (do () ((not pred?)) body ...))))
> (let ((x 4))
    (while (< x 10)
      (set! x (+ x 1)))
    x)
10

您应该与您的导师讨论您对涉及Scheme的误解。

答案 1 :(得分:-1)

我无法决定这是否是家庭作业。所以,好吧,这是一个解决这个问题的版本:如果它一个家庭作业,那么无论是谁设置它都可能是显而易见的,如果不是,那么它就是&#39有趣的是弄清楚它是如何工作的。

需要回答的一个问题是(while #f ...)应评估的内容:通过说它应该评估为(void)返回的内容来回答这个问题。这也使用(begin form ...)进行排序:严重不正当会使用((λ () form ...))而不是当然。

(define-syntax-rule (while condition form ...)
  ((λ (c) (c c (void)))
   (λ (c v)
     (if condition
         (c c (begin form ...))
         v))))

详细说明

上述原始答案是故意混淆的,因为我不想提供作业答案。这是它的未经过仿冒的版本,以及一系列混淆/净化步骤,可以产生上述结果。

首先,我想要(while condition form ...)做的是评估其中的表单,直到condition不为真,然后返回最后一个表单的值。如果condition永远不为真,请返回(void)

所以这样做的方法是使用循环,在Scheme中表达循环的一种非常自然的方式是命名为 - let。剩下的技巧是返回的值绑定在命名的 - let中,初始绑定为(void),后续的绑定是最后一个表单的结果,通过(begin form ...)。所以,我们得到了这个:

(define-syntax-rule (while condition form ...)
  (let loop ([v (void)])
    (if condition
        (loop (begin form ...))
        v)))

你可以很清楚地看到它做了它需要做的事情。

所以,第一个混淆是我们不需要使用名为 - let:我们可以使用letrec代替:

(define-syntax-rule (while condition form ...)
  (letrec ([loop (λ (v)
                   (if condition
                       (loop (begin form ...))
                       v))])
    (loop (void))))

嗯,这显然做了同样的事情:letrec建立了绑定值可见的绑定,所以这样可以正常工作。

但我讨厌letrec:我们可以不使用它吗?是的,我们可以:我们可以传递这个东西来调用函数本身:

(define-syntax-rule (while condition form ...)
  (let ([loop (λ (c v)
                (if condition
                    (c c (begin form ...))
                    v))])
    (loop loop (void))))

所以现在这个函数并不知道它自己在调用它:它只是给了一个函数来调用它本身。

最后一步是要意识到(let ((x y)) ...)((λ (x) ...) y)相同:let只是λ上的一些语法糖。所以我们重写了以前的版本来获得这个:

(define-syntax-rule (while condition form ...)
  ((λ (loop) (loop loop (void)))
   (λ (c v)
     (if condition
         (c c (begin form ...))
         v))))

这是一些变量重命名,是原始版本。