在球拍中通过循环追加的正确方法是什么?

时间:2012-07-25 23:30:43

标签: loops racket

今天开始学习球拍。我试图找到通过循环追加的正确方法,但无法找到答案或自己弄清楚语法。

例如,如果我想使用hc-append排九个圆圈,如何在不手动输入九个嵌套的hc-append程序的情况下执行此操作?

4 个答案:

答案 0 :(得分:8)

你需要意识到的第一件事是在Racket中“循环”实际上只是递归。在这种情况下,您希望将一堆绘图调用链接在一起。如果我们写出来,我们的目标就是:

(hc-append (circle 10) 
    (hc-append (circle 10)
        (hc-append (circle 10)
            (hc-append (circle 10)
                (hc-append (circle 10)
                    (hc-append (circle 10)
                        (hc-append (circle 10)
                            (hc-append (circle 10)
                                (hc-append (circle 10))))))))))

我假设我们所有的圈子都是相同的半径。

现在,既然我们要编写一个递归方法,我们需要考虑我们的基本情况。我们想要绘制九个圆圈。我们称之为最大圈数max。我们的基本情况是,当我们突破“循环”时,我们将进行max次迭代,或者(= iterations max)时。

现在为递归本身。我们已经知道我们需要传递至少两个变量,即当前迭代iterations和最大迭代max。如果你看一下上面的代码,你会发现所有“循环”中的重复元素都是(circle 10)。现在有很多方法可以传递它 - 有些人会选择仅仅通过半径 - 但我认为最简单的方法是传递圆圈的图形。

最后,我们还要传递到目前为止我们所做的图片。也就是说,当我们向我们的链附加一个圆圈时,我们需要将它传递回递归方法,以便我们可以继续追加。

现在我们已经得到了平方,我们可以定义递归方法的结构,我们称之为circle-chain-recursive

(define (circle-chain-recursive iteration max crcle output)
    ; body here
)

我们方法的“胆量”将是if。如果我们已达到最大迭代次数,则返回输出。否则添加另一个圆圈,递增iteration,然后再次调用该方法。

(define (circle-chain-recursive iteration max crcle output)
  (if (= iteration max) 
      output
      (circle-chain-recursive
        (+ 1 iteration) max crcle (hc-append crcle output))))

我个人不喜欢直接调用这样的递归循环方法,所以我会编写一个这样的辅助方法:

(define (circle-chain num radius)
  (circle-chain-recursive 0 num (circle radius) (circle 0)))

现在,如果我想要一系列10个半径为10的圆圈,我只需要拨打(circle-chain 9 10)

您会注意到我传递了(circle 0)作为名为output的参数。这是因为hc-append方法需要pict参数。由于我们没有开始使用任何圆圈,因此我将其传递给相当于“空白”或零的图像。可能还有其他方式传递“空白”图片,但我不太熟悉slideshow/pict图书馆来了解它。

我希望稍微澄清一下。

答案 1 :(得分:4)

Racket中有三种循环样式:

#1 for-loop style

此样式使用“球拍指南”第11章中描述的语法"Iterations and Comprehensions"。它看起来像这样:

(require slideshow/pict)

(for/fold ([result (blank)]) ([i (in-range 9)])
  (hc-append (circle 10) result))

在这种风格中,在 for 之后的第一个括号中定义了循环的临时变量。在我的示例中有一个这样的变量,称为 result 。然后定义迭代变量以及它们迭代的内容。所以在这里, i 循环遍历0到8的数字。循环体为每个 i 运行一次,每次将结果分配给 result < / em>,循环的最终值是最后 result 的值。

#2地图和折叠样式。

Section 3.8 of the Guide中描述了这种风格。它看起来像这样:

(require slideshow/pict)
(foldl hc-append (blank) (build-list 9 (lambda (i) (circle 10))))

此代码首先列出9个圆圈:

(define o (circle 10))
(build-list 9 (lambda (i) o)  --->  (list o o o o o o o o o)

列表表示法是更详细的缺点表示法的简写。

(list o o o o o o o o o)  --->  (cons o (cons o (cons o (cons o (cons o (cons o (cons o (cons o (cons o empty)))))))))

考虑 foldl 函数的方法是将一段数据转换为一段计算。它将列表作为输入,并将其转换为函数调用的集合。

foldl 函数获取列表并用第一个参数替换列表中的每个 cons ,并替换结尾处的 empty 。带有第二个参数的列表。在示例中,我传递了 hc-append 函数和(空白),因此替换内容如下所示:

(foldl hc-append (blank) ...) --->
(hc-append o (hc-append o (hc-append o (hc-append o (hc-append o (hc-append o (hc-append o (hc-append o (hc-append o (blank))))))))))

这个函数调用序列正是你想要避免手写的函数。 Foldl 为您计算。

#3递归样式

这是Roddy在他的回答中描述的风格。作为编码风格的一般问题,如果没有简单的* for, map fold ,则应该只使用递归样式,例如遍历递归数据时结构

答案 2 :(得分:3)

冷冻豌豆的罗迪有这个答案。

我想补充一点,因为这类事情是如此常见 - 重复一个过程并积累结果 - 在Racket语言中有一些功能可以简洁地表达这个想法。其中一个功能是Racket的for/fold循环。举个例子:

> (for/fold ([result 'Go!]) 
            ([i (in-range 5)])
    (list 'Duck result))
'(Duck (Duck (Duck (Duck (Duck Go!)))))

在这里,我们在初始值'Go!上重复操作(列出'Duck结果)以累积结果。 for / fold 的实现是基于Roddy描述的递归过程,所以一旦你掌握了基础知识,你就会知道足够轻松地使用 for / fold

答案 3 :(得分:0)

这是一篇很老的帖子,但它被高度阅读,因此我正在添加一个答案。使用'named let'的方法也非常方便:

(define (f)
  (let loop ((counter 1)
             (result (blank)))
    (if (< counter 10)
        (loop (add1 counter)
              (hc-append (circle 10) result))
        result)))