.c Thursday July 10,1980 3:59 LQ+5D.3H.56M.26S. -*- Text -*- .chapter "Introduction" LOOP is a Lisp macro which provides a programmable iteration facility. The same LOOP module operates compatibly in both Lisp Machine Lisp and Maclisp (PDP-10 and Multics). LOOP was inspired by the "FOR" facility of CLISP in InterLisp; however, it is not compatible and differs in several details. The general approach is that a form introduced by the word 3loop* generates a single program loop, into which a large variety of features can be incorporated. The loop consists of some initialization (2prologue*) code, a body which may be executed several times, and some exit (2epilogue*) code. Variables may be declared local to the loop. The features are concerned with loop variables, deciding when to end the iteration, putting user-written code into the loop, returning a value from the construct, and iterating a variable through various real or virtual sets of values. The 3loop* form consists of a series of clauses, each introduced by a keyword symbol. Forms appearing in or implied by the clauses of a 3loop* form are classed as those to be executed as initialization code, body code, and/or exit code, but aside from that they are executed strictly in the order implied by the original composition. Thus, just as in ordinary Lisp code, side-effects may be used, and one piece of code may depend on following another for its proper operation. This is the principal philosophy difference from InterLisp's "FOR" facility. Note that 3loop* forms are intended to look like stylized English rather than Lisp code. There is a notably low density of parentheses, and many of the keywords are accepted in several synonymous forms to allow writing of more euphonious and grammatical English. Some find this notation verbose and distasteful, while others find it flexible and convenient. The former are invited to stick to 3do*. .space 1 .group .lisp (defun print-elements-of-list (list-of-elements) (loop for element in list-of-elements do (print element))) .end_lisp The above function prints each element in its argument, which should be a list. It returns 3nil*. .end_group .space 1 .group .lisp (defun extract-interesting-numbers (start-value end-value) (loop for number from start-value to end-value when (interesting-p number) collect number)) .end_lisp The above function takes two arguments, which should be fixnums, and returns a list of all the numbers in that range (inclusive) which satisfy the predicate 3interesting-p*. .end_group .space 1 .group .lisp (defun find-maximum-element (array) (loop for i from 0 below (cadr (arraydims array)) maximize (funcall array i))) .end_lisp 3Find-maximum-element* returns the maximum of the elements of its argument, a one-dimensional array. .end_group .group .space 1 .lisp (defun remove (object list) (loop for element in list unless (equal object element) collect element)) .end_lisp 3Remove* is like the Lisp function 3delete*, except that it copies the list rather than destructively splicing out elements. .end_group .space 1 .group .lisp (defun find-frob (list) (loop for element in list when (frobp element) return element finally (error '|Frob not found in list| list))) .end_lisp This returns the first element of its list argument which satisfies the predicate 3frobp*. If none is found, an error is generated. .end_group .chapter "Clauses" Internally, LOOP constructs a 3prog* which includes variable bindings, pre-iteration (initialization) code, post-iteration (exit) code, the body of the iteration, and stepping of variables of iteration to their next values (which happens on every iteration after executing the body). A 2clause* consists of the keyword symbol and any other Lisp forms and keywords which it deals with. For example, .lisp (loop for x in l do (print x)), .end_lisp contains two clauses, "7for x in l*" and "7do (print x)*". Certain of the parts of the clause will be described as being 2expressions*, e.g. "(print x)" in the above. An expression can be a single Lisp form, or a series of forms implicitly collected with 3progn*. An expression is terminated by the next following atom, which is taken to be a keyword. Thus, syntax allows only the first form in an expression to be atomic, but makes misspelled keywords more easily detectable. Bindings and iteration variable steppings may be performed either sequentially or in 'cindex sequential vs parallel binding and initialization parallel, which affects how the stepping of one iteration variable may depend on the value of another. The syntax for distinguishing the two will be described with the corresponding clauses. When a set of things is "in parallel", all of the bindings produced will be performed in parallel by a single lambda binding. Subsequent bindings will be performed inside of that binding environment. .section "Iteration-Producing Clauses" These clauses all create a 2variable of iteration*, which is bound locally to the loop and takes on a new value on each successive iteration. Note that if more than one iteration-producing clause is used in the same loop, several variables are created which all step together through their values; when any of the iterations terminates, the entire loop terminates. Nested iterations are not generated; for those, you need a second 3loop* form in the body of the loop. All of the iteration-producing clauses initially defined are introduced with the keyword 3for* (or 3as*, which is synonomous). 'cindex parallel vs. sequential iteration stepping 3For* clauses may be clustered into groups, the variables of iteration of which are to be stepped in parallel, by introducing the additional clauses with 3and* instead of 3for* or 3as*. For example, the following iterates over the elements in a list, and also has a variable for the element from the previous iteration: .lisp (loop for item in list and previous-item = 'foo then item do ...) .end_lisp During the first iteration, 3previous-item* has the value 3foo*; in subsequent iterations, it has the value of 3item* from the previous iteration. Note that this would not work if the stepping were not performed in parallel. The order of evaluation in iteration-producing clauses is that 'cindex order of evaluation in iteration clauses those expressions which are only evaluated once are evaluated in order at the beginning of the form, during the variable-binding phase, while those expressions which are evaluated each time around the loop are evaluated in order in the body. These are the iteration-producing clauses. Optional parts are enclosed in curly brackets. .table 3 250 500 .item for 2var* {2data-type*} in 2expr1* {by 2expr2*} .kindex for This iterates over each of the elements in the list 2expr1*. If the 3by* subclause is present, 2expr2* is evaluated once on entry to the loop to supply the function to be used to fetch successive sublists, instead of 3cdr*. .item for 2var* on 2expr1* {by 2expr2*} .kindex for This is like the previous 3for* format, except that 2var* is set to successive tails of the list instead of successive elements. .item for 2var* {2data-type*} = 2expr* .kindex for On each iteration, 2expr* is evaluated and 2var* is set to the result. .item for 2var* {2data-type*} = 2expr1* then 2expr2* .kindex for 2Var* is bound to 2expr1* when the loop is entered, and set to 2expr2* on all succeeding iterations. .item for 2var* {2data-type*} from 2expr1* {to 2expr2*} {by 2expr3*} .kindex for 'c i can't read moon's handwriting! This performs numeric iteration. 2Var* is initialized to 2expr1*, and on each succeeding iteration is incremented by 2expr3* (default 31*). If the 3to* phrase is given, the iteration terminates when 2var* becomes greater than 2expr2*. Each of the expressions is evaluated only once, and the 3to* and 3by* phrases may be written in either order. 3Downto* may be used instead of 3to*, in which case 2var* is decremented by the step value, and the endtest is adjusted accordingly. If 3below* is used instead of 3to*, or 3above* instead of 3downto*, the iteration will be terminated before 2expr2* is reached, rather than after. Note that the 3to* variant appropriate for the direction of stepping must be used for the endtest to be formed correctly, i.e. the code will not work if 2expr3* is negative or zero. If no limit specifying clause is given, then the direction of the stepping may be specified as being decreasing by using 3downfrom* instead of 3from*. 3Upfrom* may also be used instead of 3from*; it forces the stepping direction to be increasing. The 2data-type* defaults to 3fixnum*. .item for 2var* {2data-type*} being 2expr* and its 2path* ... .item1 for 2var* {2data-type*} being {each} 2path* ... .kindex for This provides a user-definable iteration facility. 2Path* names the manner in which the iteration is to be performed. The ellipsis indicates where various path dependent preposition/expression pairs may appear. See the section on Iteration Paths ((iteration-path-page)) for complete documentation. .end_table .section "Bindings" .setq with-clause page .kindex with 'cindex variable bindings The 3with* keyword may be used to establish initial bindings, that is, variables which are local to the loop but are only set once, rather than on each iteration. The 3with* clause looks like: .lisp 3with 2var1* {2data-type*} {= 2expr1*} {and 2var2* {2data-type*} {= 2expr2*}}...* .end_lisp If no 2expr* is given, the variable is initialized to the appropriate value for its data type, usually 3nil*. 3With* bindings linked by 3and* are performed in parallel; those not linked are performed sequentially. That is, .lisp (loop with a = (foo) and b = (bar) ...) .end_lisp binds the variables like .lisp ((lambda (a b) ...) (foo) (bar)) .end_lisp whereas .lisp (loop with a = (foo) with b = (barprime a) ...) .end_lisp binds the variables like .lisp ((lambda (a) ((lambda (b) ...) (barprime a))) (foo)) .end_lisp All 2expr*'s in 3with* clauses are evaluated in the order they are written, upon entrance to the loop rather than where they appear in the body. Thus good style suggests that 3with* clauses be placed first in the loop. For binding more than one variable with no particular initialization, one may use the construct .lisp 3with 2variable-list* {2data-type-list*} {and ...}* .end_lisp as in .lisp with (i j k t1 t2) (fixnum fixnum fixnum) ... .end_lisp which is a useful special case of 2destructuring* ((destructuring-section)). .section "Entrance and Exit" .table 3 250 500 .item initially 2expression* .kindex initially This puts 2expression* into the 2prologue* of the iteration. It will be evaluated before any other initialization code other than the initial bindings. For the sake of good style, the 3initially* clause should therefore be placed after any 3with* clauses but before the main body of the loop. .item finally 2expression* .kindex finally This puts 2expression* into the 2epilogue* of the loop, which is evaluated when the iteration terminates (other than by an explicit 3return*). For stylistic reasons, then, this clause should appear last in the loop body. Note that certain clauses may generate code which terminates the iteration without running the epilogue code; this behaviour is noted with those clauses. .end_table .section "Side Effects" .setq side-effects-section css-number .table 3 250 500 .item do 2expression* .item1 doing 2expression* .kindex do doing 2Expression* is evaluated each time through the loop. .end_table .section "Values" .setq values-section css-number The following clauses accumulate a return value for the iteration in some manner. The general form is .lisp 32type-of-collection expr* {2data-type*} {into 2var*}* .end_lisp where 2type-of-collection* is a 3loop* keyword, and 2expr* is the thing being "accumulated" somehow. If no 3into* is specified, then the accumulation will be returned when the 3loop* terminates. If there is an 3into*, then when the epilogue of the 3loop* is reached, 2var* (a variable automatically bound locally in the loop) will have been set to the accumulated result and may be used by the epilogue code. In this way, a user may accumulate and somehow pass back multiple values from a single 3loop*, or use them during the loop. It is safe to reference these variables during the loop, but they should not be modified until the epilogue code of the loop is reached. For example, .lisp (loop for x in list collect (foo x) into foo-list collect (bar x) into bar-list collect (baz x) into baz-list finally (return (list foo-list bar-list baz-list))) .end_lisp which has the same effect as .lisp (do ((g0001 l (cdr g0001)) (x) (foo-list) (bar-list) (baz-list)) ((null g0001) (list (nreverse foo-list) (nreverse bar-list) (nreverse baz-list))) (setq x (car g0001)) (setq foo-list (cons (foo x) foo-list)) (setq bar-list (cons (bar x) bar-list)) (setq baz-list (cons (baz x) baz-list))) .end_lisp .table 3 250 500 .item collect 2expr* {into 2var*} .item1 collecting ... .kindex collect collecting .setq collect-clause page This causes the values of 2expr* on each iteration to be collected into a list. .item nconc 2expr* {into 2var*} .item1 nconcing ... .item1 append ... .item1 appending ... .kindex nconc nconcing append appending These are like 3collect*, but the results are 3nconc*ed or 3append*ed together as appropriate. 3collecting*:3mapcar*::3nconcing*:3mapcan*. .item count 2expr* {into 2var*} .item1 counting ... .kindex count counting If 2expr* evaluates non-3nil*, a counter is incremented. The 2data-type* is always 3fixnum*. .item sum 2expr* {2data-type*} {into 2var*} .item1 summing ... .kindex sum summing Evaluates 2expr* on each iteration, and accumulates the sum of all the values. 2Data-type* defaults to 3number*, which for all practical purposes is 3notype*. .item maximize 2expr* {2data-type*} {into 2var*} .item1 minimize ... .kindex maximize minimize Computes the maximum (or minimum) of 2expr* over all iterations. 2Data-type* defaults to 3number*. .end_table Not only may there be multiple 2accumulations* in a 'cindex multiple accumulations 3loop*, but a single 2accumulation* may come from multiple places 2within the same 3loop* form*. Obviously, the types of the collection must be compatible. 3Collect*, 3nconc*, and 3append* may all be mixed, as may 3sum* and 3count*, and 3maximize* and 3minimize*. For example, .lisp (loop for x in '(a b c) for y in '((1 2) (3 4) (5 6)) collect x append y) => (a 1 2 b 3 4 c 5 6) .end_lisp .group The following computes the average of the entries in the list 2list-of-frobs*: .lisp (loop for x in list-of-frobs count t into count-var sum x into sum-var finally (return (quotient sum-var count-var))) .end_lisp .end_group .section "Endtests" .cindex terminating the iteration The following clauses may be used to provide additional control over when the iteration gets terminated, possibly causing exit code (due to 3finally*) to be performed and possibly returning a value (e.g., from 3collect*). .table 3 250 500 .item while 2expr* .kindex while If 2expr* evaluates to 3nil*, the loop is exited, performing exit code (if any), and returning any accumulated value. The test is placed in the body of the loop where it is written. It may appear between sequential 3for* clauses. .item until 2expr* .kindex until Identical to 3while (not 2expr*)*. .end_table This may be needed, for example, to step through a strange data structure, as in .lisp (loop for concept = 2expr* then (superior-concept concept) until (eq concept [summum-genus]) ...) .end_lisp .section "Aggregated Boolean Tests" .table 3 250 500 .item always 2expr* .kindex always If 2expr* evaluates to 3nil*, the iteration is terminated and 3nil* returned; otherwise, 3t* will be returned when the loop finishes, after the epilogue code (if any, as specified with the 3finally* clause) has been run. .item never 2expr* .kindex never This is like 3always (not 2expr*)*. .item thereis 2expr* .kindex thereis If 2expr* evaluates non-3nil*, then the iteration is terminated and that value is returned, without running the epilogue code. .end_table .section "Conditionalization" .cindex conditionalizing clause(s) These clauses may be used to "conditionalize" the following clause. They may precede any of the side-effecting or value-producing clauses, such as 3do*, 3collect*, or 3always*. .table 3 250 500 .item when 2expr* .item1 if 2expr* .kindex when if .space 0 .c Make sure this starts it on a new line.... .c .break doesn't do it. .c Will a ".space 0" do it? If 2expr* evaluates to 3nil*, the following clause will be skipped, otherwise not. .item unless 2expr* .kindex unless This is equivalent to 3when (not 2expr*))*. .end_table Multiple conditionalization clauses may appear in sequence. If one test fails, then any following tests in the immediate sequence, and the clause being conditionalized, are skipped. Multiple clauses may be conditionalized under the same test by joining them with 3and*, as in .lisp (loop for i from a to b when (zerop (remainder i 3)) collect i and do (print i)) .end_lisp which returns a list of all multiples of 33* from 2a* to 2b* (inclusive) and prints them as they are being collected. Conditionals may be nested. For example, .lisp (loop for i from a to b when (zerop (remainder i 3)) do (print i) and when (zerop (remainder i 2)) collect i) .end_lisp returns a list of all multiples of 36* from 2a* to 2b*, and prints all multiples of 33* from 2a* to 2b*. Useful with the conditionalization clauses is the 3return* clause, which causes an explicit return of its "argument" as the value of the iteration, bypassing any epilogue code. That is, .lisp 3when 2expr1* return 2expr2** .end_lisp is equivalent to .lisp 3when 2expr1* do (return 2expr2*)* .end_lisp Conditionalization of one of the "aggregated boolean value" clauses simply causes the test which would cause the iteration to terminate early not to be performed unless the condition succeeds. For example, .lisp (loop for x in l when (significant-p x) do (print x) (princ "is significant.") and thereis (extra-special-significant-p x)) .end_lisp .group The format of a conditionalization and following clause is typically something like .lisp 3when 2expr1* 2keyword* 2expr2** .end_lisp If 2expr2* is the keyword 3it*, then a variable is generated to hold the value of 2expr1*, and that variable gets substituted for 2expr2*. Thus, the composition .lisp 3when 2expr* return it* .end_lisp is equivalent to the clause .lisp 3thereis 2expr** .end_lisp and one may collect all non-null values in an iteration by saying .lisp 3when 2expression* collect it* .end_lisp If multiple clauses are joined with 3and*, the 3it* keyword may only be used in the first. If multiple 3when*s, 3unless*es, and/or 3if*s occur in sequence, the value substituted for 3it* will be that of the last test performed. .end_group .chapter "LOOP Synonyms" .defmac define-loop-macro .lisp (define-loop-macro 2keyword*) .end_lisp may be used to make 2keyword*, a 3loop* keyword (such as 3for*), into a LISP macro which may introduce a 3loop* form. For example, after evaluating .lisp (define-loop-macro for), .end_lisp one may now write an iteration as .lisp (for i from 1 below n do ...) .end_lisp .end_defmac .chapter "Data Types" .setq data-type-section page .cindex data type keywords In many of the clause descriptions, an optional 2data-type* is shown. A 2data-type* in this sense is an atomic symbol, and is recognizable as such by LOOP. LOOP interfaces to a module which defines how declarations and initializations are to be performed for various data types. However, it recognizes several types specially so that that module need not be present in order for them to be used: .table 3 250 500 .item fixnum An implementation-dependent limited range integer. .item flonum An implementation-dependent limited precision floating point number. .item integer Any integer (no range restriction). .item number Any number. .item notype Unspecified type (i.e., anything else). .end_table .chapter "Destructuring" .setq destructuring-section page 2Destructuring* provides one with the ability to "simultaneously" assign or bind multiple variables to components of some data structure. Typically this is used with list structure (which is the only mode currently supported). For example, .lisp (desetq (foo . bar) '(a b c)) .end_lisp has the effect of setting 3foo* to 3a* and 3bar* to 3(b c)*. LOOP only requires destructuring support when one of these patterns is supplied in place of a variable. In addition, the "binding" of a pattern to a constant 3nil* is so treated that it requires no special support code; this allows the case .lisp with (a b c) .end_lisp to work without destructuring support code. One may specify the data types of the components of a pattern by using a corresponding pattern of the data type keywords in place of a single data type keyword. This syntax remains unambiguous because wherever a data type keyword is possible, a 3loop* keyword is the only other possibility. Thus, if one wants to do .lisp (loop for x in l as i fixnum = (car x) and j fixnum = (cadr x) and k fixnum = (cddr x) ...) .end_lisp and no reference to 3x* is needed, one may instead write .lisp (loop for (i j . k) (fixnum fixnum . fixnum) in l ...) .end_lisp To allow some abbreviation of the data type pattern, an atomic data type component of the pattern is considered to state that all components of the corresponding part of the variable pattern are of that type. That is, the previous form could be written as .lisp (loop for (i j . k) fixnum in l ...) .end_lisp This generality allows binding of multiple typed variables in a reasonably concise manner, as in .lisp (loop with (a b c) and (i j k) fixnum ...) .end_lisp which binds 3a*, 3b*, and 3c* to 3nil* and 3i*, 3j*, and 3k* to 30* for use as temporaries during the iteration, and declares 3i*, 3j*, and 3k* to be fixnums for the benefit of the compiler. .lisp .space 1 (defun map-over-properties (fn symbol) (loop for (propname propval) on (plist symbol) by 'cddr do (funcall fn symbol propname propval))) .end_lisp .space 1 See also section (dependencies-section), (dependencies-section-page), which discusses support code needed in various implementations. .chapter "Iteration Paths" .setq iteration-path-page page Iteration paths provide a mechanism for user extension of iteration-producing clauses. The interface is constrained so that the definition of a path need not depend on much of the internals of LOOP. In general, a path iteration has one of the forms .lisp for 2var* {2data-type*} being 2expr0* and its 2pathname* {2preposition1* 2expr1*}... for 2var* {2data-type*} being {each} 2pathname* of 2expr0* {2preposition1* 2expr1*} .end_lisp The difference between the two is this: in the first, 2var* will take on the value of 2expr0* the first time through the loop; but in the second, it will be the "first step along the path". 2Pathname* is an atomic symbol which is defined as a 3loop* path function. The usage and defaulting of 2data-type* is up to the path function. Any number of preposition/expression pairs may be present; the prepositions allowable for any particular path are defined by that path. The 3of* preposition has special meaning in that it specifies the starting point of the path; thus, the first variation shown implicitly uses an 3of* 2expr0* "prepositional phrase". To enhance readability, pathnames are usually defined in both the singular and plural forms. To satisfy the anthropomorphic among you, 3his*, 3her*, or 3their* may be substituted for the 3its* keyword. Egocentricity is not condoned. One pre-defined path is 3cars*; it simply iterates over successive 3car*s of its starting argument, terminating after an atom is reached. For example, .lisp (loop for x being cars of '((a b) c) collect x) => ((a b) a) (loop for x being '((a b) c) and its cars collect x) => (((a b) c) (a b) a) .end_lisp The above forms are equivalent to .lisp (loop for x = (car '((a b) c)) then (car x) collect x until (atom x)) .end_lisp and .lisp (loop for x = '((a b) c) then (car x) collect x until (atom x)) .end_lisp respectively. (Note that the 3atom* check following the body of this loop is part of the definition of the 3cars* path, and is not a property of paths in general.) .group By special dispensation, if a 2pathname* is not recognized, then the 3attachments* path will be invoked upon a syntactic transformation of the original input. This name derives historically from its original usage in XLMS. Essentially, the 3loop* fragment .lisp for 2var* being 2a-r* of 2expr* ... .end_lisp is taken as if it were .lisp for 2var* being attachments in 2a-r-** of 2expr* ... .end_lisp and .lisp for 2var* being 2expr* and its 2a-r* ... .end_lisp is taken as if it were .lisp for 2var* being 2expr* and its attachments in 2a-r-** .end_lisp Thus, this "undefined pathname hook" only works if the 3attachments* path is defined. Note also: .defvar loop-attachment-transformer The value of this is a function of one argument which will be called on 2a-r* to transform it into 2a-r-**. If it is 3nil*, then a 3quote* is listed around the expression, effectively causing the special 3attachments* syntax to be an unevaluated form of the 3attachments* path. This is initially 3nil* except in an LMS environment, in which case it is a function which simply returns 2a-r*. .end_defvar .end_group .need 6000 .c 6 inches -- don't want the section header to come out all alone. .section "Defining Paths" This section will probably be of interest only to those interested in defining their own paths. For the purposes of discussion, the general template form of an iteration may be assumed to be .lisp (let 2variable-bindings* (prog () 2prologue-code* next-loop 2pre-body-endtests-1* 2pre-body-steps-1* 2pre-body-endtests-2* 2pre-body-steps-2* ... 2body* 2post-body-endtests-1* 2post-body-steps-1* 2post-body-endtests-2* 2post-body-steps-2* ... (go next-loop) end-loop 2epilogue-code* )) .end_lisp When more than one 3for* clause is grouped together with 3and*, the endtests and steps are arranged to occur together in parallel. Sequentially arranged 3for* clauses cause multiple endtests and steps to occur one after another, as shown in the above template. A function to generate code for a path may be declared to 3loop* with the 3define-loop-path* function: .defun define-loop-path pathname-or-names path-function list-of-allowable-prepositions (1any-number-of*data) This defines 2path-function* to be the handler for the path(s) 2pathname-or-names*, which may be either a symbol or a list of symbols. Such a handler should follow the conventions described below. .end_defun The handler will be called with the following arguments: .table 2 250 500 .item path-name The name of the path which caused the path function to be invoked. .item variable The "iteration variable". .item data-type The data type supplied with the iteration variable, or 3nil* if none was supplied. .item prepositional-phrases This is a list with entries of the form 2(preposition expression)*, in the order in which they were collected. This may also include some supplied implicitly (e.g. 3of* phrases, and 3in* phrases for attachment relations); the ordering will show the order of evaluation which should be followed for the expressions. .item inclusive? This is 3t* if 2variable* should have the starting point of the path as its value on the first iteration, 3nil* otherwise. .item allowed-prepositions This is the list of allowable prepositions declared for the pathname that caused the path function to be invoked. It and 2data* (immediately below) may be used by the path function such that a single function may handle similar paths. .item data This is the list of "data" declared for the pathname that caused the path function to be invoked. It may, for instance, contain a canonicalized pathname, or a set of functions or flags to aid the path function in determining what to do. In this way, the same path function may be able to handle different paths. .end_table The handler should return a list with the following elements: .table 2 250 500 .item variable-bindings This is a list of variables which need to be bound. The entries in it may be of the form 2variable*, (2variable* 2expression*), or (2variable* 2expression* 2data-type*). Note that it is the responsibility of the handler to make sure the iteration variable gets bound. All of these variables will be bound in parallel; thus, if initialization of one depends on others, it should be done with a 3setq* in the 2prologue-forms*. .item prologue-forms This is a list of forms which should be included in the loop prologue. .item pre-body-endtest This is a single form. .item pre-body-steps This should be an alternating list of variables and expressions to step them. They will be stepped in parallel. (This is like the arguments to 3setq*; in fact, it will be used as the arguments to 3psetq*.) .item post-body-endtest Like 2pre-body-endtest*, but done after the 2body*, just before starting the next iteration. .item post-body-steps Like 2pre-body-steps*. .end_table If anyone finds that they need to modify the 2main* body or the epilogue code, we would like to hear about it. A qualification is in order with respect to stepping. In order to make parallel stepping work properly, 3loop* must be able to coerce the stepping code for different 3for* clauses to act in parallel. Thus, the canonical place for stepping to occur is in the 2post-body-steps*; the 2pre-body-steps* is mainly useful when the iteration variable needs to be set to some function of whatever is actually being iterated over. For example, the LOOP clause .lisp 3for 2var* in 2list** .end_lisp effectively returns the following elements for the template (where 2tem* is really a gensymed variable name): .table 2 250 500 .item variable-bindings 3(2var* (2tem* 2list*))* .item prologue-forms 3nil* .item pre-body-endtest 3(null 2tem*)* .item pre-body-steps 3(2var* (car 2tem*))* .item post-body-endtest 3nil* .item post-body-steps 3(2tem* (cdr 2tem*))* .end_table .defun loop-tequal token symbol-or-string This is the LOOP token comparison function. 2Token* is any Lisp object; 2symbol-or-string* is the keyword it is to be compared against. It returns 3t* if they represent the same token, comparing in a manner appropriate for the implementation. In certain implementations 3loop-tequal* may be a macro. .end_defun .chapter "Compatibility with FOR" LOOP is not truly compatible with FOR (a similar Maclisp iteration package). The reason for this is that LOOP has certain "ideas" about how it should handle such things as order of evaluation and repeated evaluation, which are quite different from FOR's simpler template approach. Many of the keywords, and hopefully all of the functionality, have been preserved. In many cases, code written with FOR will work with LOOP, although it sometimes may not behave identically. For convenience, here is a (non-exhaustive) summary of the major differences. One major difference is that LOOP is more fastidious about how it orders the assignments and endtests. Take, for example .lisp (loop for n in list as z = (* n n) collect z) .end_lisp In FOR, 3n* would be assigned to the 3car* of the list, then 3z* would be stepped, and then the 3null* check would be made on the iteration list. This means that on the last iteration 3z* will be assigned to 3(* nil nil)*, which might cause some consternation to the Lisp interpreter. In LOOP, first a 3null* check is made on the list, then 3n* is set to the 3car* of the list, then 3z* is stepped. Explicit endtests (3while* and 3until*) are placed "where they appear" in the iteration sequence. This obviates the 3repeat-while* and 3repeat-until* keywords of FOR. For example, the FOR construct .lisp (for x in l collect x repeat-while (< x 259.)) .end_lisp may be replaced by the LOOP construct .lisp (loop for x in l collect x while (< x 259.)) .end_lisp Note that in the FOR case, the ordering of the clauses typically does not matter, but in the LOOP case it typically does. Thus, the ordering in .lisp (loop for data = (generate-some-data) collect (f data) while (test data)) .end_lisp causes the result to be a list with at least one element. LOOP attempts to suppress repeated evaluation where possible. Which expressions get repeatedly evaluated is documented with the corresponding clauses. One significant example where LOOP and FOR differ is in the case .lisp (loop for i from 0 to 2expression* ...) .end_lisp in which FOR evaluates 2expression* at every iteration, whereas LOOP saves the value at the start of the iteration. It should be noted that the conditionalization clauses (3when*, 3until*, and 3if*) affect only the following clause rather than the whole of the "body" of the iteration, as would be the case in FOR. Because it is difficult for it to work in all cases, the 3trailing* clause has been eliminated. Its effect may be achieved, however, by tacking .lisp and 2var* = 2initial-value* then 2var-to-be-trailed* .end_lisp after the 3for* clause which steps 2var-to-be-trailed*. .chapter "Dependencies" .setq dependencies-section css-number .setq dependencies-section-page page The LOOP package may require the existence of other routines in some implementations. For efficiency reasons, LOOP avoids producing 3let* in the code it generates unless it is necessary for destructuring bindings. In the PDP-10 Maclisp implementation, LOOP uses 3ferror* to generate error messages; 3ferror* is part of the FORMAT package, and is assumed to be autoloadable from there. 3Let*, which is used to produce destructuring bindings, and the destructuring version of 3setq* called 3desetq*, which is used only when destructuring is used, are both autoloadable. The "parallel setq" mechanism is simulated so that 3psetq* is not needed. Macro memoizing is performed using the same facilities which 3defmacro* uses, and are autoloadable (and typically present in most environments). In Multics Maclisp, LOOP does not presently call 3ferror*, which does not exist. There is a 3let* macro available with destructuring capability; it is non-standard (not part of the Multics Lisp system) -- for further information contact the authors. Currently, macro memoizing is performed by 3rplaca*/3rplacd* splicing, unconditionally. In Lisp Machine lisp, 3ferror* is used to generate errors. This is part of the basic Lisp Machine environment. At this time, destructuring support is not part of the basic environment, although it is available; contact either the authors or the Lisp Machine group if you need this. Macro memoizing is performed using 3displace*, with the same effect as in Multics Maclisp. .c Local Modes: .c Auto Fill Mode:1 .c Comment Start:.c .c Comment Begin:.c .c Comment End: .eof