"做什么"控制构造在Scheme中做什么?

时间:2016-12-11 12:28:16

标签: algorithm scheme procedure

我违反了一个使用所谓do程序的Scheme程序,但我不知道它是如何工作的,或者它是如何实现的。如果有人可以提供帮助,我将非常感激。 代码如下:

(define (storage-move-right vector i j)
  (do ((idx j (- idx 1)))
    O(n)
      ((< idx i))
        (vector-set! vector (+ idx 1) (vector-ref vector idx))))

1 个答案:

答案 0 :(得分:2)

&#34;失踪&#34;循环构造while,repeat-until和for

问题

控件构造whilerepeat-untilfor存在于大多数主流编程语言中,但是在Scheme标准中找不到它们。 Scheme中使用了什么?

解决方案

这些结构都可以被模仿&#34;通过使用正常(尾递归)函数调用。然而,由于经常使用这些构建体,因此可获得一些更方便的合成糖。最常用的两个构造使用named letdo构造。

最好将do构造视为荣耀的&#34; do-until&#34; -loop。最简单的do形式是:

(do ()
  [test return-exp]
  exp
  ...)

如果省略return-exp,则返回值为void,&#34;不可见值&#34; (如此命名是因为它没有在交互窗口中打印出来。)

在每个循环开始时,评估测试表达式。如果它是非假的,则评估return-exp并且其返回值是整个do - 循环的值。如果测试为假,则按顺序评估正文表达式。评估完最后一个正文表达式后,将启动一个新循环。

; Example 1
; WARNING: This is not good style.
;          A better solution is found below.

                                  ; Pseudo Code
(define i 0)                      ; i := 0
(do ()                            ; do 
  [(= i 5)]                       ;   until i=5
  (display i)                     ;       display i
  (set! i (+ i 1)))               ;       i := i +1

; displays: 01234

do的替代品,即#34;名为let&#34;是let语法的变体,它提供比do更通用的循环结构,也可用于表示递归。它具有与普通let几乎相同的语法,但是可以在正文中使用变量名来使用新值var1重复执行body ...通过使用new调用name值。

(let name ([var1 exp1]
           ...)
   body
   ...)

变量列表可以为空。 重写正常的while -loop现在很容易:

while test           (do ()                 (let while ()
  begin                [(not test)]           (when test
    exp1               exp1                      exp1
    exp2               exp2                      exp2
    ...                ...)                      ...
  end                                            (while)))

(void)表达式计算为&#34;不可见&#34; value表示不打算使用返回值。它不是由交互窗口(REPL)打印的。

使用for撰写do - 循环要求我们查看下一个最简单的形式:

(do ([var start-exp next-exp])
  [test return-exp]
  exp
  ...)

do - 表达式的评估始于对start-exp的评估。结果绑定到变量i,该变量在next-exp以及testreturn-expbody表达式中均可见。当重新启动循环时,next-exp被评估,变量var被反弹到结果,在test表达式和(可能)重新评估正文之前。

; Example 2
(do ([i 0 (+ i 1)])           (let loop ([i 0])
  [(= i 5)]                     (unless (= i 5)
  (display i))                     (display i)
                                   (loop (+ i 1))))
; displays: 01234

现在很清楚如何使用do:

编写正常的for循环
for i=a to b step d         (do ([i a (+ i d)])          (let for ([i a])
  begin                       [(> i b)]                    (unless (> i b)
    exp1                      exp1                            exp1
    exp2                      exp2                            exp2
    ...                       ...)                            ...
  end                                                         (for (+ i d))))

使用repeat-until编写do循环很麻烦,但使用命名let我们可以执行以下操作:

repeat                
  begin        (let loop ()         (let loop ()
    exp1         exp1                 exp1
    exp2         exp2                 exp2
    ...          ...                  ...
  end            (if (not test)       (unless test (loop)))
until test           (loop)))

此答案基于SchemeCookbook中的条目。查看档案:https://web.archive.org/web/20131004034526/http://schemecookbook.org/Cookbook/IdiomLoopingConstructs