1
0
mirror of https://github.com/PDP-10/its.git synced 2026-01-13 15:27:28 +00:00
PDP-10.its/doc/libdoc/for.info
2018-05-07 08:40:52 +02:00

276 lines
12 KiB
Common Lisp
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;-*-Lisp-*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ITERATION FUNCTIONS ;;;
;;; Peter Szolovits (PSZ @ MIT-ML) ;;;
;;; July 16, 1976 ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; revised by PSZ & RAMESH on Mar. 22, 1979 ;;;
;;; revised by LH@MIT-ML on May 9, 1979 ;;;
;;; revised again by BYRON@MIT-ML on July 12, 1979 ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;This package defines a set of functions to provide an
;;;approximation of INTERLISP's iteration statement facility
;;;within a MACRO package for MACLISP.
;;;
;;;
;;;For the simplest exposition of its use and utility, here are
;;;a few examples of how the iterations statements may be used:
;;;
;;; (FOR I FROM 1 TO 3 COLLECT I) ==> (1 2 3)
;;;
;;; (COLLECT (CONS I X) FOR X IN '(A B C D E) AS I BY 3)
;;; ==> ((1 . A) (4 . B) (7 . C) (10 . D) (13 . E))
;;;
;;; (UNLESS (ATOM X) JOIN X FOR X IN '((A B C) (D E) F (G)))
;;; ==> (A B C D E G)
;;;
;;; (FOR X ON '(A B C D) AS I FROM 1 ADJOIN (PRINT I) X)
;;; 1
;;; 2
;;; 3
;;; 4
;;; ==> (A B C D B C D C D D)
;;;
;;; (FIRST (SETQ FOO '(A B (C D) E))
;;; WHILE (ATOM (CAR FOO)) DO (SETQ FOO (CDR FOO)) (PRINT FOO))
;;; (B (C D) E)
;;; ((C D) E)
;;; ==> NIL
;;;
;;; (BIND X (FOO '(A B (C D) E))
;;; WHILE (ATOM (SETQ X (CAR FOO)))
;;; COLLECT (SETQ FOO (CDR FOO)) (CONS X X))
;;; ==> ((A . A) (B . B))
;;;
;;; (FOR X IN '(A B C D) FIRST-TIME (MEMQ X '(E F G C 1 2 3)))
;;; ==> (C 1 2 3)
;;;
;;;FOR now supports LET-type "destructuring" wherever variables are
;;; explicitly bound (by BIND, FOR, or AS) so:
;;;
;;; (FOR (X Y) IN '((1 2) (3 4)) COLLECT (+ X Y) ==> (3 7)
;;;
;;; (BIND ((X Y) '(2 4)) FOR I FROM 1 TO 2 COLLECT (+ X Y I)) ==> (7 8)
;;;
;;*page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; GENERAL DESCRIPTION ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; An ITERATION is a convenient manner of writing a complex
;;;LISP looping expression when control is desired of various
;;;aspects of the iteration which make the system-provided
;;;functions (e.g., MAPCAR, DO) too rigid or too cumbersome.
;;;
;;; An iteration statement consists of a number of clauses,
;;;described below, written in succession within a single S-EXPR.
;;;
;;; Every iteration has at most one MAIN CLAUSE, which
;;;controls what, if anything, is collected as the result of the
;;;iteration. The default provided main clauses are:
;;;
;;; DO (or DOING) -- evaluated for side-effect only; return is
;;; NIL.
;;; COLLECT -- A list of the values of every evaluation of the
;;; main clause is returned (c.f. MAPCAR).
;;; JOIN -- The values of every evaluation of the main clause
;;; are NCONCed together to form the value (c.f.
;;; MAPCAN).
;;; ADJOIN -- Like JOIN, but joining is by APPEND rather than
;;; NCONC. Every joined segment is copied exactly
;;; once, even if there is only one segment.
;;; COUNT -- The number of non-NIL values of the evaluations of
;;; the main clause is returned.
;;; SUM -- The sum of the values of the evaluations of the main
;;; clause is returned.
;;; FIRST-TIME -- The value of the iteration is the first
;;; non-NIL value of the main clause, and iteration
;;; terminates when and if this occurs.
;;; PRINT (or PRINTING) -- PRINT's the values of the evaluations
;;; of the main clause.
;;; RESULT -- Sets the RESULT variable to the value of the expression
;;; and exits.
;;;
;;;Other main clauses may be added. Each must be signalled by a
;;;keyword marked by the !FUNCTION property with an appropriate
;;;function to fill in the iteration template for it.
;;;
;;;
;;; The binding of LOOP VARIABLES and AUXILLIARY VARIABLES is
;;;controlled by the BIND, FOR and AS clauses. The BIND keyword is
;;;followed by the variables or (variable initial-val) or
;;;(variable-structure initial-val) <as in LET> forms to be
;;;bound. Those variables are bound, and the initial-vals are evaluated
;;;before any of the bindings for this iteration. The FOR and AS
;;;clauses are equivalent and provide a way to have several loop
;;;variables. The keyword is followed by the name of the variable, and
;;;optionally by FIXNUM, FLONUM, or NOTYPE. NOTYPE is the default
;;;except for numeric (FROM, TO, DOWNTO, BY) variables, for which it is
;;;FIXNUM. An appropriate declaration to the compiler is made. The rest
;;;of each variable clause has one of the following forms:
;;;
;;; FROM e1 TO e2 BY e3 -- This is the numeric iteration clause.
;;; Its terms may appear in any order. Instead of
;;; the TO, we may have a DOWNTO term to indicate
;;; that the loop is for decrementing the var. FROM
;;; defaults to 1, BY to 1 with TO and -1 with
;;; DOWNTO. Incrementing is assumed if neither is
;;; stated. (Currently, no checking is performed to
;;; see that the types of args are consistent, and
;;; the type of arithmetic used is determined by the
;;; type specified. NOTYPE implies general
;;; arithmetic, and the default is FIXNUM.)
;;; IN list -- This is iteration over a list. The var gets
;;; successive elements of the list.
;;; ON list -- This is iteration over successive tails of the
;;; list.
;;; STARTING e1 STEPPING e2 -- This is a general form for giving
;;; initial and incremental values. The terms may
;;; be in either order. STARTING defaults to NIL,
;;; and if STEPPING is omitted, no stepping action
;;; is set up.
;;; TRAILING v1, or TRAILS v1 -- The iteration variable will take on the
;;; value that v1 had on the previous iteration. V1 should
;;; be some other iteration variable of this iteration. On
;;; the first iteration, since there is no previous value of
;;; v1, we use NIL.
;;; SET-TO e1, or = e1 -- On each iteration, e1 is evaluated and
;;; assigned to the variable. This is most useful when e1
;;; is expressed in terms of some other iteration
;;; variable(s). E1 is always computed in terms of the new
;;; values of the iteration variables, not the old.
;;; BEING pathname OF e1, or
;;; BEING e1 AND ITS pathname -- These are the exclusive and
;;; inclusive forms of the PATH ITERATION.
;;; Pathnames must be explicitly marked by the
;;; !PATH-FUNCTION property with a function to
;;; process them. This is a special feature, most
;;; useful for LMS and OWL, and in this package
;;; there are no paths defined by default. The
;;; keyword ALONG is synonymous with BEING. Note
;;; that there are variants of these subclauses, not
;;; described here, that are specifically tailored
;;; for iterating through the objects in a zone of
;;; an LMS node; these variants are recognized by
;;; the fact that EACH occurs where the pathname or
;;; ITS would normally have occurred.
;;;
;;; The sub-keywords like FROM, IN, etc., are recognized by having an
;;;!ITER-FUNCTION property; thus, others may be added to the package.
;;;
;;; TERMINATION CLAUSES allow specification of additional
;;; iteration termination conditions beyond any that are
;;; implied by FOR and AS clauses. The following exist:
;;;
;;; WHILE e1 -- e1 is evaluated at the beginning of each
;;; iteration, and the iteration terminates when e1
;;; is NIL.
;;; UNTIL e1 -- like WHILE but terminates when e1 is non-NIL.
;;; REPEAT-WHILE e1 -- e1 is evaluated at the end of each
;;; iteration, and the iteration terminates when e1
;;; is NIL; this guarantees at least one
;;; iteration.
;;; REPEAT-UNTIL e1 -- like REPEAT-WHILE but terminates when e1 is
;;; non-NIL.
;;;
;;;
;;; A SELECTION-CLAUSE is a filter on which iteration the
;;;main clause should be evaluated. A conjunction is implied if more
;;; than one selection exists. The following exist:
;;; WHEN e1 -- The main clause is evaluated if e1 is non-NIL.
;;; UNLESS e1 -- The main clause is evaluated if e1 is NIL.
;;;
;;;
;;; The PERIPHERAL CLAUSES are of three kinds:
;;;
;;; FIRST e1 -- Evaluates e1 after initially binding the vars
;;; but before starting the first iteration.
;;; FINALLY e1 -- Evaluates e1 after exiting the last iteration
;;; but before returning the answer. If the main
;;; clause is a value-returning clause, the result
;;; to be returned is in the variable RESULT (see notes).
;;; EACH-TIME e1 -- Evaluates e1 on every iteration of the loop,
;;; whether or not the selection test is passed.
;;;
;;*page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; CAVEATS ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;
;;; A few notes should be made about implementation features
;;;which affect the evaluation of iteration forms:
;;;
;;; 1. Like in the LISP DO, initialization and updating of the
;;;iteration variables takes place in parallel. Only SET-TO varaibles
;;;and their internally generated equivalents (e.g., "X in Y") are done
;;;after the others, and these should never lead to trouble. This is a
;;;significant change from earlier versions of the FOR package.
;;;
;;; 2. The iteration statement is translated to a LISP DO. In
;;;particular, this means that a (RETURN val) form may be
;;;evaluated at any place to return that particular val as the
;;;value of the iteration. If it is desired that any FINALLY
;;;clauses be evaluated and the value returned, then the
;;; following may be done:
;;; (SETQ RESULT val), if appropriate and if the main clause
;;; is value-returning
;;; (TERMINATE-ITERATION)
;;;Note that the RESULT clause may be used in many cases where this is
;;;desired.
;;;
;;; 3. Wherever possible, the order of evaluation of
;;;expressions whose evaluation order is not otherwise
;;;constrained is that suggested by the order of writing them in
;;;the iteration statement. This is only of significance if
;;;significant use of side effects is made.
;;;
;;; 4. Wherever a single expression may appear, more than one
;;;may appear. They will be implicitly surrounded by a PROGN,
;;;so all but the last will be evaluated for side effect only.
;;;
;;; 5. The name RESULT, in which the value of value-collecting
;;;iterations is built up, is selected only by default. If the
;;;value of the variable !RESULT-NAME is bound, that will be
;;;used instead.
;;;
;;; 6. Almost no error checking is currently done, so it is
;;;possible to get weird errors if the iterative statement is
;;;not well-formed.
;;;
;;; 7. This code is written using (I think) only one macro,
;;;!PUSH, which is not part of the standard LISP complement.
;;;!PUSH is defined herein to be equivalent to PUSH with its
;;;arguments reversed, except that it only works for simple
;;;(atomic) variables.
;;;
;;; 8. For efficiency, translations produced by these macros
;;;are saved in the array !MACRO-EXPANSIONS and further calls on
;;;the same form are translated by retrieval rather than
;;;recomputation. This, however, may cause some problems: For
;;;efficiency considerations (i.e., SXHASH or EQUAL are slow),
;;;retrieval is done by EQ comparison on the form. Thus, if the
;;;form has been edited since its original translation, an
;;;incorrect translation will be retrieved. Further, since all
;;;translated forms are referred to from !MACRO-EXPANSIONS, many
;;;un-garbage-collectable obsolete copies of a form can be
;;;retained during debugging runs. (E.g., if one keeps
;;;redefining some function which includes macro calls. For
;;;anyone who thinks they can solve this problem by retrieval on
;;;the MAKNUM of the form or by making the array untraced by the
;;;GC, be warned that either "fix" causes mis-translations.) The
;;;function !MACRO-FLUSH is provided to flush all existing
;;;translations and guarantee that new translations of all these
;;;macro forms are made. This also releases for
;;;garbage-collection all the "old" forms which are only pointed
;;;at by this translation mechanism.