在 Racket 中,我可能会使用for/fold
列表理解来编写它:
(define (weights-to-range weights)
(define-values (xs _)
(for/fold ([xs '()] [prev 0])
([weight (in-list weights)])
(define this (+ prev weight))
(values (cons this xs) this)))
(reverse xs))
(require rackunit)
(check-equal? (weights-to-range '(1 4 6 6 6 6 6))
'(1 5 11 17 23 29 35))
除了这个之外,它会更简单,因为这提供了两个累积值fold/fold
- xs
并且prev
-for/fold
表单将返回两个值。因此,我们需要将两者都放入临时变量中define-values
,然后再传递我们关心的一个 - 从xs
- 到reverse
。(varprev
被命名为_
。这只是一个约定,意思是“忽略”,因为我们不需要它。)
当然,这里的一般想法是使用成对的“滑动窗口”来“折叠”列表,到目前为止,累积结果可用于每个步骤。在您的情况下,函数是+
,但可以概括为:
(define (fold-slide f vs)
(define-values (xs _)
(for/fold ([xs '()] [prev 0])
([v (in-list vs)])
(define this (f prev v))
(values (cons this xs) this)))
(reverse xs))
有了这样一个fold-slide
(因为没有更好的名字)函数,你可以简单地写:
(fold-slide + '(1 4 6 6 6 6 6)
fold-slide
如果它可以处理任何大小的“窗口”,而不仅仅是 2,那么它可能会更有用。
ps 完全有可能有一些 SRFI 做这样的事情,或者在 Racket 中做这件事的更优雅的方式,我不知道。