Changeset 2539 in project

11/28/06 07:02:14 (15 years ago)

Changes applied for Alex Shinn ( through svnwiki:

Expanding on iterators; minor tweaks.

1 edited


  • wiki/loopy-loop

    r2538 r2539  
     1[[tags: egg]]
    13[[tags: egg]]
    5759  (x <- in-list ls)
    59 This will bind X to the succesive elements of LS in the body of the
     61This will bind X to the successive elements of LS in the body of the
    7678according to whatever logic we want, and re-enter it possibly multiple
    7779times.  However, in this common case where the entire body is reduced
    78 to just calling the loop again, we can ommit it by using an anonymous
     80to just calling the loop again, we can omit it by using an anonymous
    9193and it works as expected.
    93 === Bindings and scope
     95=== Bindings and Scope
    9597Iterator macros may introduce variables in three different lexical
    121123to it.
    123 Loop variables may be manually overriden on a recursive call.  You can
     125Loop variables may be manually overridden on a recursive call.  You can
    124126either use the original positional arguments, or specify individual
    125127values by name with the <- syntax, punning the initial binding.  Thus
    151153           (lp res <- (cons x res))))))
    153 The scope of the final expression will include all the final loop
     155The scope of the final expression will include all the final
     156variables, as well as all the last instances of all the loop
    154157variables, at least one of which will correspond to a true termination
    155 condition.  The body variables are not bound, however the loop itself,
    156 if named, is available so that you can restart the loop with all new
    157 initial values if you want.
     158condition (you could manually check the others to see if the sequence
     159lengths were uneven).  The body variables are not bound, however the
     160loop itself, if named, is available so that you can restart the loop
     161with all new initial values if you want.
    159163=== Iterators
    161165* (<element> [<pair>] <- in-list <list> [<cdr> [<null?>]])
     167Iterates over the successive elements of a list.
    163169  ;;; Simple loop
    165170  > (loop ((x <- in-list '(a b c))) (write x) (newline))
    166171  a
    170175  ;;; Reverse a list destructively.
    172176  (define (reverse! list)
    173177    (loop ((elt pair <- in-list list)
    174178           (tail '() pair))
    175       => tail
     179        => tail
    176180      (set-cdr! pair tail)))
    178182  ;;; Test for circularity
    180183  (define (cddr* ls) ; CL's cddr
    181     (let ((x (cdr ls))) (if (pair? x) (cdr x) '())))
     184    (if (pair? (cdr ls)) (cddr ls) '()))
    183186  (define (circular-list? ls)
    190193* (<elements> [<pairs>] <- in-lists <lol> [<cdr> [<null?>]])
     195Iterate over a list of lists.  <elements> is bound to the heads of
     196each of the lists in <lol>.  The CDR and NULL? options can be
     197specified as in IN-LIST.
     199  (define (any pred . lol)
     200    (loop lp ((elts <- in-lists lol))
     201        => #f
     202      (or (apply pred elts) (lp))))
    192204* (<element> [<index>] <- in-string <str> [<start> [<end> [<step>]]])
    193205* (<element> [<index>] <- in-string-reverse <str> [<start> [<end> [<step>]]])
     207Iterate over the characters of a string.  Proceeds from <start>,
     208inclusive, to <end>, exclusive.  By default <start> is 0 and <end> is
     209the string length, thus iterating over every character.
     211You can specify a step other than the default 1, for example 2 to
     212iterate over every other character.
     214The reverse version steps from one less than the end, continuing until
     215you step below the start.  Thus with the same <start> and <end> and a
     216<step> of 1 (or any divisor of the difference), the two forms will
     217iterate over the same characters but in the reverse order.
     219Note this works correctly with the utf8 egg, but is not optimal in
     220such cases because the use of numeric indexes is slow.
    194222* (<element> [<index>] <- in-vector <vec> [<start> [<end> [<step>]]])
    195223* (<element> [<index>] <- in-vector-reverse <vec> [<start> [<end> [<step>]]])
     225Analogues of the string iterators, but for vectors.
    197227* (<datum> <- in-port [<port> [<reader> [<eof?>]]])
    198 * (<datum> <- in-file [<port> [<reader> [<eof?>]]])
     228* (<datum> <- in-file <path> [<reader> [<eof?>]])
     230Iterate over data read from a port, defaulting to (CURRENT-INPUT-PORT)
     231for IN-PORT, and a port opened by (OPEN-INPUT-FILE <path>) for
     232IN-FILE.  The reader defaults to READ-CHAR?, and the termination test
     233defaults to EOF-OBJECT?.
     235The stateful nature of ports means that these are not referentially
     236transparent, and you can't save a loop iteration to go back to later.
     237In particular, IN-FILE will close its port on the first termination,
     238causing an error if you attempt to re-enter the same loop again.
     240  (define (read-mime-headers port)
     241    (loop lp ((line <- in-port port read-line)
     242              (res '() (cons line res)))
     243        => (reverse res) ; eof case
     244      (if (string-null? line)
     245        (reverse res)
     246        (lp))))
     248  ;; alternate version with a custom termination test
     249  (define (read-mime-headers port)
     250    (loop lp ((line <- in-port port read-line
     251                       (disjoin eof-object? string-null?))
     252              (res <- collecting line))
     253        => res))
     255  (define (file->sexp-list path)
     256    (loop ((x <- in-file path read) (ls <- collecting x)) => x))
    200258* (<number> <- in-range [[<from>] <to> [<step>]])
    201259* (<number> <- in-range-reverse [[<from>] <to> [<step>]])
     261Step through the real numbers beginning with <from> (default 0), until
     262they would be greater than (less then in the -reverse case) or equal
     263to <to> (thus <to> is never included).  <step> defaults to 1.
     265Two arguments indicate <from> and <to>, so provide the default <from>
     266of 0 if you're only interested in <to> and <step>.
     268These macros are subject to change in the near future.
    203270* (<number> <- in-random [<range> [<low>]])
    204 * (<number> <- in-random-element <vector-or-list>)
    206 * (<number> <- in-permutations <list> [<n>])
    207 * (<number> <- in-combinations <list> <n>)
     272With no arguments, <number> is bound to a random inexact number
     273uniformly distributed over 0.0 and 1.0, inclusive, on each iteration.
     275With a single argument, <number> is bound to a random integer
     276uniformly distributed over 0..<range>-1, inclusive.
     278With two arguments, <number> is bound to a random integer uniformly
     279distributed over <low>..<low>+<range>-1, inclusive.
     281These are conceptually infinite sequences, and themselves never cause
     282the loop to terminate.
     284* (<element> <- in-random-element <vector-or-list>)
     286On each iteration, <element> is bound a random object uniformly
     287chosen from the elements of the <vector-or-list> source.
     289Elements may be repeated, so this is a conceptually infinite sequence.
     291* (<perm> <- in-permutations <list> [<n>])
     293With one argument, <perm> is bound to the successive permutations of
     294the elements of <list> in lexicographic order.  No assumptions about
     295the elements are made - if <list> is a multi-set, duplicate
     296permutations will arise.
     298This is very fast and mutation free.  It uses only O(k) space, where k
     299is the number of elements in <list>.  Beware that the number of
     300permutations of n elements is n!, which grows extremely fast.
     302  > (loop ((p <- in-permutations '(a b c) 2)) (write p) (newline))
     303  (a b)
     304  (a c)
     305  (b a)
     306  (b c)
     307  (c a)
     308  (c b)
     310* (<comb> <- in-combinations <list> <n>)
     312Similar to IN-PERMUTATIONS, but iterates over all combinations of <n>
     313elements from <list> (i.e. order doesn't matter).
     315  > (loop ((c <- in-combinations '(a b c) 2)) (write c) (newline))
     316  (a b)
     317  (a c)
     318  (b c)
     320Using permutations and combinations can be a convenient way to build
     321very extensive (albeit brute-force) test suites, among other things.
    209323* (<key> <value> <- in-hash-table <table>)
    211 * (<list> <- collecting <expr> [<cons> [<final>]])
     325Iterate over the <key> and <value> pairs of a hash-table <table>.  The
     326current <key> being iterated over may be deleted from the table or
     327have its value in the table changed safely.
     329The result is unspecified if you add or remove other values to the
     330table while it is being iterated over.  If you want to capture a safe
     331snapshot of the table first, you can convert it to an alist and
     332iterate over those values.
     334  (define (hash-table-purge! pred table)
     335    (loop ((k v <- in-table table))
     336      (if (pred k v)
     337        (hash-table-delete! table k))))
     339* (<list> [<rev>] <- collecting <expr> [<cons> [<finalize> [<init>]]])
     341The only of the standard iterators that introduces a final variable.
     342<list> is bound only in the => final clause.  By default
     344A <cons> of APPEND-REVERSE will append all the <expr>'s into a list.
     346A <finalize> of REVERSE-LIST->VECTOR, this will collect a vector, and
     347IDENTIFY will collect a reversed list.
     349By specifying all of <cons>, <finalize> and <init> you could collect
     350into any data structure.
     352The optional <rev> is a loop variable representing the intermediate
     353consed results.  You may override this manually to include or exclude
     354values, or even reset the collected results mid-loop.
     356This is really just syntactic sugar over an accumulated list to save
     357you the trouble of reversing manually at the end.
    214359=== Extending
Note: See TracChangeset for help on using the changeset viewer.