Changeset 2539 in project


Ignore:
Timestamp:
11/28/06 07:02:14 (15 years ago)
Author:
svnwiki
Message:

Changes applied for Alex Shinn (219.163.97.121) through svnwiki:

Expanding on iterators; minor tweaks.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wiki/loopy-loop

    r2538 r2539  
     1[[tags: egg]]
     2
    13[[tags: egg]]
    24
     
    5759  (x <- in-list ls)
    5860
    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
    6062loop.
    6163
     
    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
    7981loop:
    8082
     
    9193and it works as expected.
    9294
    93 === Bindings and scope
     95=== Bindings and Scope
    9496
    9597Iterator macros may introduce variables in three different lexical
     
    121123to it.
    122124
    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))))))
    152154
    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.
    158162
    159163=== Iterators
     
    161165* (<element> [<pair>] <- in-list <list> [<cdr> [<null?>]])
    162166
     167Iterates over the successive elements of a list.
     168
    163169  ;;; Simple loop
    164 
    165170  > (loop ((x <- in-list '(a b c))) (write x) (newline))
    166171  a
     
    169174
    170175  ;;; Reverse a list destructively.
    171 
    172176  (define (reverse! list)
    173177    (loop ((elt pair <- in-list list)
    174178           (tail '() pair))
    175       => tail
     179        => tail
    176180      (set-cdr! pair tail)))
    177181
    178182  ;;; Test for circularity
    179 
    180183  (define (cddr* ls) ; CL's cddr
    181     (let ((x (cdr ls))) (if (pair? x) (cdr x) '())))
     184    (if (pair? (cdr ls)) (cddr ls) '()))
    182185
    183186  (define (circular-list? ls)
     
    190193* (<elements> [<pairs>] <- in-lists <lol> [<cdr> [<null?>]])
    191194
     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.
     198
     199  (define (any pred . lol)
     200    (loop lp ((elts <- in-lists lol))
     201        => #f
     202      (or (apply pred elts) (lp))))
     203
    192204* (<element> [<index>] <- in-string <str> [<start> [<end> [<step>]]])
    193205* (<element> [<index>] <- in-string-reverse <str> [<start> [<end> [<step>]]])
     206
     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.
     210
     211You can specify a step other than the default 1, for example 2 to
     212iterate over every other character.
     213
     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.
     218
     219Note this works correctly with the utf8 egg, but is not optimal in
     220such cases because the use of numeric indexes is slow.
     221
    194222* (<element> [<index>] <- in-vector <vec> [<start> [<end> [<step>]]])
    195223* (<element> [<index>] <- in-vector-reverse <vec> [<start> [<end> [<step>]]])
    196224
     225Analogues of the string iterators, but for vectors.
     226
    197227* (<datum> <- in-port [<port> [<reader> [<eof?>]]])
    198 * (<datum> <- in-file [<port> [<reader> [<eof?>]]])
     228* (<datum> <- in-file <path> [<reader> [<eof?>]])
     229
     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?.
     234
     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.
     239
     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))))
     247
     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))
     254
     255  (define (file->sexp-list path)
     256    (loop ((x <- in-file path read) (ls <- collecting x)) => x))
    199257
    200258* (<number> <- in-range [[<from>] <to> [<step>]])
    201259* (<number> <- in-range-reverse [[<from>] <to> [<step>]])
    202260
     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.
     264
     265Two arguments indicate <from> and <to>, so provide the default <from>
     266of 0 if you're only interested in <to> and <step>.
     267
     268These macros are subject to change in the near future.
     269
    203270* (<number> <- in-random [<range> [<low>]])
    204 * (<number> <- in-random-element <vector-or-list>)
    205 
    206 * (<number> <- in-permutations <list> [<n>])
    207 * (<number> <- in-combinations <list> <n>)
     271
     272With no arguments, <number> is bound to a random inexact number
     273uniformly distributed over 0.0 and 1.0, inclusive, on each iteration.
     274
     275With a single argument, <number> is bound to a random integer
     276uniformly distributed over 0..<range>-1, inclusive.
     277
     278With two arguments, <number> is bound to a random integer uniformly
     279distributed over <low>..<low>+<range>-1, inclusive.
     280
     281These are conceptually infinite sequences, and themselves never cause
     282the loop to terminate.
     283
     284* (<element> <- in-random-element <vector-or-list>)
     285
     286On each iteration, <element> is bound a random object uniformly
     287chosen from the elements of the <vector-or-list> source.
     288
     289Elements may be repeated, so this is a conceptually infinite sequence.
     290
     291* (<perm> <- in-permutations <list> [<n>])
     292
     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.
     297
     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.
     301
     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)
     309
     310* (<comb> <- in-combinations <list> <n>)
     311
     312Similar to IN-PERMUTATIONS, but iterates over all combinations of <n>
     313elements from <list> (i.e. order doesn't matter).
     314
     315  > (loop ((c <- in-combinations '(a b c) 2)) (write c) (newline))
     316  (a b)
     317  (a c)
     318  (b c)
     319
     320Using permutations and combinations can be a convenient way to build
     321very extensive (albeit brute-force) test suites, among other things.
    208322
    209323* (<key> <value> <- in-hash-table <table>)
    210324
    211 * (<list> <- collecting <expr> [<cons> [<final>]])
    212 
     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.
     328
     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.
     333
     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))))
     338
     339* (<list> [<rev>] <- collecting <expr> [<cons> [<finalize> [<init>]]])
     340
     341The only of the standard iterators that introduces a final variable.
     342<list> is bound only in the => final clause.  By default
     343
     344A <cons> of APPEND-REVERSE will append all the <expr>'s into a list.
     345
     346A <finalize> of REVERSE-LIST->VECTOR, this will collect a vector, and
     347IDENTIFY will collect a reversed list.
     348
     349By specifying all of <cons>, <finalize> and <init> you could collect
     350into any data structure.
     351
     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.
     355
     356This is really just syntactic sugar over an accumulated list to save
     357you the trouble of reversing manually at the end.
    213358
    214359=== Extending
Note: See TracChangeset for help on using the changeset viewer.