В 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
. (Переменная для prev
называется _
. Это просто соглашение, означающее «игнорируется», потому что оно нам не нужно.)
Конечно, общая идея здесь состоит в том, чтобы «свернуть» список, используя «скользящее окно» пар, с совокупным результатом, доступным на каждом этапе. В вашем случае функция +
, но ее можно обобщить:
(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.
p.s. Вполне возможно, что есть какой-то SRFI, который делает что-то подобное, или более элегантный способ сделать это в Racket, чего я не знаю.
person
Greg Hendershott
schedule
07.09.2013