#reader(lib "docreader.ss" "scribble") @require[(lib "manual.ss" "scribble")] @require[(lib "eval.ss" "scribble")] @require[(lib "bnf.ss" "scribble")] @require["guide-utils.ss"] @interaction-eval[(require (lib "list.ss"))] @interaction-eval[(require (lib "for.ss"))] @define[step @elem{=}] @title{Lists, Iteration, and Recursion} Scheme is a dialect of the language Lisp, whose name originally stood for ``LISt Processor.'' The built-in list datatype remains a prominent feature of the language. The @scheme[list] procedure takes any number of values and returns a list containing the values: @interaction[(list "red" "green" "blue") (list 1 2 3 4 5)] As you can see, a list result prints in the REPL as a pair of parentheses wrapped around the printed form of the list elements. There's an opportunity for confusion here, because parentheses are used for both expressions, such as @scheme[(list "red" "green" "blue")], and printed results, such as @schemeresult[("red" "green" "blue")]. Rememeber that, in the documentation and in DrScheme, parentheses for results are printed in blue, whereas parentheses for expressions are brown. Many predefined procedures operate on lists. Here are a few examples: @interaction[ (code:line (length (list "a" "b" "c")) (code:comment #, @t{count the elements})) (code:line (list-ref (list "a" "b" "c") 0) (code:comment #, @t{extract by position})) (list-ref (list "a" "b" "c") 1) (code:line (append (list "a" "b") (list "c")) (code:comment #, @t{combine lists})) (code:line (reverse (list "a" "b" "c")) (code:comment #, @t{reverse order})) (code:line (member "d" (list "a" "b" "c")) (code:comment #, @t{check for an element})) ] @;------------------------------------------------------------------------ @section{Predefined List Loops} In addition to simple operations like @scheme[append], Scheme includes procedures that iterate over the elements of a list. These iteration procedures play much the same role as @tt{for} in Java and other languages. The body of a Scheme iteration is packaged into a procedure to be applied to each element, so the @scheme[lambda] form becomes particularly handy in combination with iteration procedures. Different list-iteration procedures combine iteration results in different ways. The @scheme[map] procedure uses the per-element results to create a new list: @interaction[ (map sqrt (list 1 4 9 16)) (map (lambda (i) (string-append i "!")) (list "peanuts" "popcorn" "crackerjack")) ] The @scheme[andmap] and @scheme[ormap] procedures combine the results by @scheme[and]ing or @scheme[or]ing: @interaction[ (andmap string? (list "a" "b" "c")) (andmap string? (list "a" "b" 6)) (ormap number? (list "a" "b" 6)) ] The @scheme[filter] procedure keeps elements for which the body result is true, and discards elements for which it is @scheme[#f]: @interaction[ (filter string? (list "a" "b" 6)) (filter positive? (list 1 -2 6 7 0)) ] The @scheme[map], @scheme[andmap], @scheme[ormap], and @scheme[filter] procedures can all handle multiple lists, instead of just a single list. The lists must all have the same length, and the given procedure must accept one argument for each list: @interaction[ (map (lambda (s n) (substring s 0 n)) (list "peanuts" "popcorn" "crackerjack") (list 6 3 7)) ] The @scheme[foldl] procedure generalizes some iteration procedures. It uses the per-element procedure to both process an element and combine it with the ``current'' value, so the per-element procedure takes an extra first argument. Also, a starting ``current'' value must be provided before the lists: @interaction[ (foldl (lambda (v elem) (+ v (* elem elem))) 0 '(1 2 3)) ] Despite its generality, @scheme[foldl] is not as popular as the other procedures. One reason is that @scheme[map], @scheme[ormap], @scheme[andmap], and @scheme[filter] cover the most common kinds of list loops. @;------------------------------------------------------------------------ @section{Iterative Folds and Comprehensions: @scheme[fold-for] and @scheme[list-for]} Besides iteration procedures like @scheme[foldl], Scheme provides a syntactic form for iteration that more closely resembles the syntax of other languages. The @scheme[foldl] example above can be written with the @scheme[fold-for] syntax as follows: @interaction[ (fold-for ([sum 0]) ([elem (list 1 2 3)]) (+ sum (* elem elem))) ] Compare to analogous Java code, where @scheme[(list 1 2 3)] is replaced by a collection @scheme[lst]: @verbatim[ #<