In Racket I would probably write it using the for/fold
list comprehension:
(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))
It would be even simpler except that, since this supplies two accumulation values to the fold/fold
-- xs
and prev
-- the for/fold
form is going to return two values. So we need to tuck both into temporary vars using define-values
, before passing the one we care about -- from xs
-- to reverse
. (The var for prev
is named _
. That's just a convention meaning "ignored", because we don't need it.)
Of course, the general idea here is to "fold" a list using a "sliding window" of pairs, with the cumulative result so far available to each step. In your case, the function is +
, but it could be generalized:
(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))
With such a fold-slide
(for lack of a better name) function, you could have written simply:
(fold-slide + '(1 4 6 6 6 6 6)
Such a fold-slide
might be even more useful if it could handle "windows" of any size, not just 2.
p.s. It's entirely possible there is some SRFI that does something like this, or a more-elegant way to do it in Racket, that I don't know.