争夺功能如何工作? (经验丰富的Schemer的第1章)
根据这本书,这是函数定义的内容,
功能争夺的元组不超过其自身索引,并返回相同长度的元组。参数中的每个数字都被视为从其自身位置到元组早期的向后索引。每个位置的结果是通过根据此索引从当前位置向后计数来获得的。
这些是一些示例,
; Examples of scramble
(scramble '(1 1 1 3 4 2 1 1 9 2)) ; '(1 1 1 1 1 4 1 1 1 9)
(scramble '(1 2 3 4 5 6 7 8 9)) ; '(1 1 1 1 1 1 1 1 1)
(scramble '(1 2 3 1 2 3 4 1 8 2 10)) ; '(1 1 1 1 1 1 1 1 2 8 2)
这是实现,
(define pick
(λ (i lat)
(cond
((eq? i 1) (car lat))
(else (pick (sub1 i)
(cdr lat))))))
(define scramble-b
(lambda (tup rev-pre)
(cond
((null? tup) '())
(else
(cons (pick (car tup) (cons (car tup) rev-pre))
(scramble-b (cdr tup)
(cons (car tup) rev-pre)))))))
(define scramble
(lambda (tup)
(scramble-b tup '())))
According to the book, this is what the function definition is,
The function scramble takes a non-empty tuple in which no argument is greater than its own index and returns a tuple of same length. Each number in the argument is treated as a backward index from its own position to a point earlier in tuple. The result at each position is obtained by counting backward from the current position according to this index.
And these are some examples,
; Examples of scramble
(scramble '(1 1 1 3 4 2 1 1 9 2)) ; '(1 1 1 1 1 4 1 1 1 9)
(scramble '(1 2 3 4 5 6 7 8 9)) ; '(1 1 1 1 1 1 1 1 1)
(scramble '(1 2 3 1 2 3 4 1 8 2 10)) ; '(1 1 1 1 1 1 1 1 2 8 2)
Here is the implementation,
(define pick
(λ (i lat)
(cond
((eq? i 1) (car lat))
(else (pick (sub1 i)
(cdr lat))))))
(define scramble-b
(lambda (tup rev-pre)
(cond
((null? tup) '())
(else
(cons (pick (car tup) (cons (car tup) rev-pre))
(scramble-b (cdr tup)
(cons (car tup) rev-pre)))))))
(define scramble
(lambda (tup)
(scramble-b tup '())))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在这种情况下,使用非常最小的语言版本意味着代码足够详细,以至于理解算法并不容易。
解决这个问题的一种方法是用更丰富的语言编写程序,然后确定现在很明显的算法如何在最低版本中实现。让我们选择球拍作为丰富的语言。
球拍具有一个函数(和方案),称为
list-ref
:(list-ref li)
返回i
的TH元素l
,基于零。它也有一个很好的“序列”概念,这些序列几乎是“您可以迭代的东西”和一堆构造,其名称以为 for 开始,以迭代序列。有两个功能使我们关心的序列:
in-Naturals
是自然数的无限序列,默认情况下是从0
开始的,但是(在-naturals n)
从n
开始。in-list
从列表中制作一个序列(列表实际上已经是一个序列,但是in-list
使事情变得更清晰,并且谣言也更快)。我们关心的迭代构造是/列表,它通过某些序列进行迭代,并将其从身体收集到列表中。
鉴于这些,那么算法几乎是微不足道的:我们想沿列表迭代,跟踪当前索引,然后进行适当的扣除以在列表中更进一步。唯一的非平凡位是处理零与一个基于索引的零。
实际上,如果我们导致
naturals
从1
计数,该算法非常清楚,您可以检查它在书中给出答案:
现在仍然可以阐明书中代码如何实现相同的算法。那是一个贴心的,但是一旦您知道算法是什么,它应该很简单。
This is a case where using a very minimal version of the language means that the code is verbose enough that understanding the algorithm is not perhaps easy.
One way of dealing with this problem is to write the program in a much richer language, and then work out how the algorithm, which is now obvious, is implemented in the minimal version. Let's pick Racket as the rich language.
Racket has a function (as does Scheme) called
list-ref
:(list-ref l i)
returns thei
th element ofl
, zero-based.It also has a nice notion of 'sequences' which are pretty much 'things you can iterate over' and a bunch of constructs whose names begin with
for
for iterating over sequences. There are two functions which make sequences we care about:in-naturals
makes an infinite sequence of the natural numbers, which by default starts from0
, but(in-naturals n)
starts fromn
.in-list
makes a sequence from a list (a list is already a sequence in fact, butin-list
makes things clearer and there are rumours also faster).And the iteration construct we care about is
for/list
which iterates over some sequences and collects the result from its body into a list.Given these, then the algorithm is almost trivial: we want to iterate along the list, keeping track of the current index and then do the appropriate subtraction to pick a value further back along the list. The only non-trivial bit is dealing with zero- vs one-based indexing.
And in fact if we cause
in-naturals
to count from1
we can avoid the awkward adding-1:Now looking at this code, even if you don't know Racket, the algorithm is very clear, and you can check it gives the answers in the book:
Now it remains to work out how the code in the book implements the same algorithm. That's fiddly, but once you know what the algorithm is it should be straightforward.
如果口头描述看起来模糊且难以遵循,我们可以尝试遵循代码本身,将其变成更为视觉的伪代码,
因此,
因此,输入列表中的每个元素都用作索引中的索引中的索引中的相反前缀。列表,直到和包括该元素。换句话说,在计数 backwards 时,一个索引从元素到左,IE,to list的 start 。
因此,我们现在已经可视化了代码在做什么,并且还发现了其输入列表元素的要求。
If the verbal description looks vague and hard to follow, we can try following the code itself, turning it into a more visual pseudocode as we go:
Thus,
Thus each element in the input list is used as an index into the reversed prefix of that list, up to and including that element. In other words, an index into the prefix while counting backwards, i.e. from the element to the left, i.e. towards the list's start.
So we have now visualized what the code is doing, and have also discovered requirements for its input list's elements.