Reduction of Lists - MIT/GNU Scheme 9.1
Description: MIT/GNU Scheme 9.1

Next: Miscellaneous List Operations, Previous: Mapping of Lists, Up: Lists

### 7.8 Reduction of Lists

— procedure: reduce-left procedure initial list

> Combines all the elements of list using the binary operation procedure. For example, using `+` one can add up all the elements:

>               (reduce-left + 0 list-of-numbers)

> The argument initial is used only if list is empty; in this case initial is the result of the call to `reduce-left`. If list has a single argument, it is returned. Otherwise, the arguments are reduced in a left-associative fashion. For example:

>               (reduce-left + 0 '(1 2 3 4))            => 10
>               (reduce-left + 0 '(1 2))                => 3
>               (reduce-left + 0 '(1))                  => 1
>               (reduce-left + 0 '())                   => 0
>               (reduce-left + 0 '(foo))                => foo
>               (reduce-left list '() '(1 2 3 4))       => (((1 2) 3) 4)

— procedure: reduce-right procedure initial list

> Like `reduce-left` except that it is right-associative.

>               (reduce-right list '() '(1 2 3 4))      => (1 (2 (3 4)))

— procedure: fold-right procedure initial list

> Combines all of the elements of list using the binary operation procedure. Unlike `reduce-left` and `reduce-right`, initial is always used:

>               (fold-right + 0 '(1 2 3 4))             => 10
>               (fold-right + 0 '(foo))                 error--> Illegal datum
>               (fold-right list '() '(1 2 3 4))        => (1 (2 (3 (4 ()))))

> `Fold-right` has interesting properties because it establishes a homomorphism between (`cons`, `()`) and (procedure, initial). It can be thought of as replacing the pairs in the spine of the list with procedure and replacing the `()` at the end with initial. Many of the classical list-processing procedures can be expressed in terms of `fold-right`, at least for the simple versions that take a fixed number of arguments:

>               (define (copy-list list)
>                 (fold-right cons '() list))

>               (define (append list1 list2)
>                 (fold-right cons list2 list1))

>               (define (map p list)
>                 (fold-right (lambda (x r) (cons (p x) r)) '() list))

>               (define (reverse items)
>                 (fold-right (lambda (x r) (append r (list x))) '() items))

— procedure: fold-left procedure initial list

> Combines all the elements of list using the binary operation procedure. Elements are combined starting with initial and then the elements of list from left to right. Whereas `fold-right` is recursive in nature, capturing the essence of `cdr`-ing down a list and then computing a result, fold-left is iterative in nature, combining the elements as the list is traversed.

>               (fold-left list '() '(1 2 3 4))         => ((((() 1) 2) 3) 4)

>               (define (length list)
>                 (fold-left (lambda (sum element) (+ sum 1)) 0 list))

>               (define (reverse items)
>                 (fold-left (lambda (x y) (cons y x)) () items))

— procedure: any predicate list list ...

> (SRFI 1) Applies predicate across the lists, returning true if predicate returns true on any application.

> If there are n list arguments list1 ... listn, then predicate must be a procedure taking n arguments and returning a boolean result.

> `any` applies predicate to the first elements of the list parameters. If this application returns a true value, `any` immediately returns that value. Otherwise, it iterates, applying predicate to the second elements of the list parameters, then the third, and so forth. The iteration stops when a true value is produced or one of the lists runs out of values; in the latter case, `any` returns `#f`. The application of predicate to the last element of the lists is a tail call.

> Note the difference between `find` and `any`—`find` returns the element that satisfied the predicate; `any` returns the true value that the predicate produced.

> Like `every`, `any`'s name does not end with a question mark—this is to indicate that it does not return a simple boolean (`#t` or `#f`), but a general value.

>               (any integer? '(a 3 b 2.7))   => #t
>               (any integer? '(a 3.1 b 2.7)) => #f
>               (any < '(3 1 4 1 5)
>                      '(2 7 1 8 2)) => #t

> The non-standard procedure `there-exists?` is similar, except that it takes a single list and a predicate argument, in that order.

— procedure: every predicate list list ...

> (SRFI 1) Applies predicate across the lists, returning true if predicate returns true on every application.

> If there are n list arguments list1 ... listn, then predicate must be a procedure taking n arguments and returning a boolean result.

> `every` applies predicate to the first elements of the list parameters. If this application returns false, `every` immediately returns false. Otherwise, it iterates, applying predicate to the second elements of the list parameters, then the third, and so forth. The iteration stops when a false value is produced or one of the lists runs out of values. In the latter case, `every` returns the true value produced by its final application of predicate. The application of predicate to the last element of the lists is a tail call.

> If one of the clisti has no elements, `every` simply returns `#t`.

> Like `any`, `every`'s name does not end with a question mark—this is to indicate that it does not return a simple boolean (`#t` or `#f`), but a general value.

> The non-standard procedure `for-all?` is similar, except that it takes a single list and a predicate argument, in that order.