PSL Manual                    7 February 1983               Flow Of Control
section 9.0                                                        page 9.1

                                 CHAPTER 9
                                 CHAPTER 9
                                 CHAPTER 9
                              FLOW OF CONTROL
                              FLOW OF CONTROL
                              FLOW OF CONTROL




     9.1. Introduction  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .     9.1
     9.2. Conditionals  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .     9.1
          9.2.1. Conds and Ifs.  .  .  .  .  .  .  .  .  .  .  .  .     9.1
          9.2.2. The Case Statement .  .  .  .  .  .  .  .  .  .  .     9.3
     9.3. Sequencing Evaluation  .  .  .  .  .  .  .  .  .  .  .  .     9.4
     9.4. Iteration  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .     9.7
          9.4.1. For .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .     9.8
          9.4.2. Mapping Functions  .  .  .  .  .  .  .  .  .  .  .    9.13
          9.4.3. Do  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .    9.16
     9.5. Non-Local Exits  .  .  .  .  .  .  .  .  .  .  .  .  .  .    9.18




9.1. Introduction
9.1. Introduction
9.1. Introduction

  Most of the constructs presented in this Chapter have a special syntax in
RLISP.    This  syntax  is  presented  along  with  the  definitions of the
underlying functions.  Many  of  the  examples  are  presented  using  this
special RLISP syntax as well as LISP.



9.2. Conditionals
9.2. Conditionals
9.2. Conditionals


9.2.1. Conds and Ifs
9.2.1. Conds and Ifs
9.2.1. Conds and Ifs


 Cond
 Cond  _ ____ ____    ___                              ____ ________  _____
(Cond [U:form-list]): any                              open-compiled, fexpr

                          Cond                    If
                          Cond                    If
     The  LISP  function  Cond corresponds to the If statement of most
                                                                    If
                                                                    If
     programming languages.  In RLISP this is simply the  familiar  If
         Then     Else
         Then     Else
     ... Then ... Else construct.  For example:

           _________      ______
        IF predicate THEN action1
              ______
         ELSE action2

                      _________ ______
           ==> (COND (predicate action1)
                        ______
                     (T action2))

     ______                        _________
     Action1  is  evaluated if the predicate has a non-NIL evaluation;
                                                Else
                ______                          Else
     otherwise, action2 is evaluated.  Dangling Elses are resolved  in
                                                                 Then
                                                                 Then
     the ALGOL manner by pairing them with the nearest preceding Then.
     For example:
Flow Of Control               7 February 1983                    PSL Manual
page 9.2                                                        section 9.2

        IF F(X) THEN
         IF G(Y) THEN PRINT(X)
          ELSE PRINT(Y);

     is equivalent to

        IF F(X) THEN
         << IF G(Y) THEN PRINT(X)
             ELSE PRINT(Y) >>;

     Note that if F(X) is NIL, nothing is printed.

     Taken  simply  as a function, without RLISP syntax, the arguments
        Cond
        Cond
     to Cond have the form:

               _________ ______ ______
        (COND (predicate action action ...)
               _________ ______ ______
              (predicate action action ...)
              ...
               _________ ______ ______
              (predicate action action ...) )

     The predicates are evaluated in the  order  of  their  appearance
     until  a non-NIL value is encountered.  The corresponding actions
     are evaluated and the value of the last becomes the value of  the
     Cond                Else
     Cond                Else
     Cond.  The dangling Else example above is:

        (COND ((F X) (COND ((G X) (PRINT X))
                           ( T    (PRINT Y)) ) ))

                                                           Go  Return
                                                           Go  Return
     The  actions  may  also contain the special functions Go, Return,
     Exit      Next
     Exit      Next
     Exit, and Next, subject to the constraints on placement of  these
                                                         Cond
                                                         Cond
     functions  given  in  Section 9.3.  In these cases, Cond does not
     have a defined value, but rather an effect.  If no  predicate  is
                           Cond
                           Cond
     non-NIL, the value of Cond is NIL.

  The  following  MACROs  are defined in the USEFUL module for convenience,
and are mostly used from LISP syntax:


 If
 If _ ____ __ ____  _ ____    ___                                     _____
(If E:form S0:form [S:form]): any                                     macro

     If                                                        Cond
     If                                                        Cond
     If is a macro to simplify the writing of a common form of Cond in
     which there are only two clauses and the antecedent of the second
     is T. It cannot be used in RLISP syntax.  

        (IF E S0 S1...Sn)

                     __                                          _
     The then-clause S0 is evaluated if and only  if  the  test  E  is
                                             _
     non-NIL,  otherwise  the  else-clauses  Si are evaluated, and the
     last returned.  There may be no else-clauses.

  Related macros for common COND forms are WHEN and UNLESS.  
PSL Manual                    7 February 1983               Flow Of Control
section 9.2                                                        page 9.3

 When
 When _ ____  _ ____    ___                                           _____
(When E:form [S:form]): any                                           macro

        (WHEN E S1 S2 ... Sn)

     evaluates  the  Si and returns the value of Sn if and only if the
                                   When
          _                        When
     test E is non-NIL.  Otherwise When returns NIL.


 Unless
 Unless _ ____  _ ____    ___                                         _____
(Unless E:form [U:form]): any                                         macro

        (UNLESS E S1 S2 ... Sn) 

                                                   _
     Evaluates the Si if and  only  if  the  test  E  is  NIL.  It  is
     equivalent to 

        (WHEN (NOT E) S1 S2 ... Sn)

         And      Or
         And      Or
  While  And  and Or are primarily of interest as Boolean connectives, they
are often used in LISP as conditionals.  For example, 

   (AND (FOO) (BAR) (BAZ))

has the same result as 

   (COND ((FOO) (COND ((BAR) (BAZ)))))

See Section 4.2.3.


9.2.2. The Case Statement
9.2.2. The Case Statement
9.2.2. The Case Statement

  PSL  provides  a  numeric  case  statement,  that   is   compiled   quite
efficiently;  some effort is made to examine special cases (compact vs. non
compact sets of cases, short vs. long sets of cases, etc.). It  has  mostly
been  used  in  SYSLISP  mode, but can also be used from LISP mode provided
that case-tags are numeric.    There  is  also  an  FEXPR,  CASE,  for  the
interpreter.

  The RLISP syntax is:


Case-Statement ::= CASE expr OF case-list END

Case-list      ::=  Case-expr [; Case-list ]

Case-expr      ::=  Tag-expr : expr

tag-expr       ::=  DEFAULT | OTHERWISE  |
                    tag | tag, tag ... tag |
                    tag TO tag

Tag            ::=  Integer | Wconst-Integer
Flow Of Control               7 February 1983                    PSL Manual
page 9.4                                                        section 9.2


For example:

        CASE i OF
           1:       Print("First");
           2,3:     Print("Second");
           4 to 10: Print("Third");
           Default: Print("Fourth");
        END



  The RLISP syntax parses into the following LISP form:  


 Case
 Case _ ____  _ ____ ____    ___                       ____ ________  _____
(Case I:form [U:case-list]): any                       open-compiled, fexpr

     _                              _______
     I  is  meant to evaluate to an integer, and is used as a selector
                         _
     amongst the various Us. Each case-list has  the  form  (case-expr
     form) where case-expr has the form:

        NIL              -> default case
        (I1 I2 ... In)   -> where each Ik is an integer or
        (RANGE low high)

     The above example becomes:

        (CASE i ((1)            (Print "First"))
                ((2 3)          (Print "Second"))
                (((Range 4 10)) (Print "Third"))
                ( NIL           (Print "Fourth")))

  [???  Perhaps  we  should  move  SELECTQ (and define a SELECT) from the
  [???  Perhaps  we  should  move  SELECTQ (and define a SELECT) from the
  [???  Perhaps  we  should  move  SELECTQ (and define a SELECT) from the
  COMMON module to the basic system ???]
  COMMON module to the basic system ???]
  COMMON module to the basic system ???]

  .



9.3. Sequencing Evaluation
9.3. Sequencing Evaluation
9.3. Sequencing Evaluation

  These  functions  provide  for  explicit  control  sequencing,  and   the
definition of blocks altering the scope of local variables.


 ProgN
 ProgN  _ ____    ___                                  ____ ________  _____
(ProgN [U:form]): any                                  open-compiled, fexpr

     _
     U  is  a set of expressions which are executed sequentially.  The
     value returned is the value of the last expression.
PSL Manual                    7 February 1983               Flow Of Control
section 9.3                                                        page 9.5

 Prog2
 Prog2 _ ____ _ ____   ___                              ____ ________  ____
(Prog2 A:form B:form): any                              open-compiled, expr

                          _
     Returns the value of B (the second argument).

  [??? Redefine prog2 to take N arguments, return second. ???]
  [??? Redefine prog2 to take N arguments, return second. ???]
  [??? Redefine prog2 to take N arguments, return second. ???]


 Prog1
 Prog1  _ ____    ___                                                 _____
(Prog1 [U:form]): any                                                 macro

     Prog1
     Prog1
     Prog1  is  a  function  defined in the USEFUL package; to use it,
                          Prog1
                          Prog1
     type (LOAD USEFUL).  Prog1 evaluates its arguments in order, like
     ProgN
     ProgN
     ProgN, but returns the value of the first.


 Prog
 Prog ____ __ ____  _______  __ ____     ___           ____ ________  _____
(Prog VARS:id-list [PROGRAM:{id,form}]): any           open-compiled, fexpr

                                                              Prog
     ____      ____    __                                     Prog
     VARS is a list of ids which are considered FLUID if the  Prog  is
     interpreted  and  LOCAL  if  compiled  (see  the  "Variables  and
                                     Prog
                                     Prog
     Bindings" Section, 10.2).  The  Prog's  variables  are  allocated
                     Prog
                     Prog
     space  if  the  Prog  form is applied, and are deallocated if the
     Prog             Prog
     Prog             Prog
     Prog is exited.  Prog variables are  initialized  to  NIL.    The
     _______
     PROGRAM is a set of expressions to be evaluated in order of their
                          Prog
                          Prog            __________
     appearance  in  the  Prog function.  identifiers appearing in the
                      _______
     top level of the PROGRAM are labels which can be referred  to  by
     Go                               Prog
     Go                               Prog
     Go.    The value returned by the Prog function is determined by a
     Return                        Prog
     Return                        Prog
     Return function or NIL if the Prog "falls through".

  There are restrictions as to where a number of control functions, such as
Go     Return
Go     Return
Go and Return, may be placed.  This is so that they may have  only  locally
determinable  effects.  Unlike most LISPs, which make this restriction only
in compiled code, PSL enforces this restriction uniformly in both  compiled
and  interpreted  code.    Not  only  does  this help keep the semantics of
compiled and interpreted code the same, but we believe  it  leads  to  more
readable  programs.  For cases in which a non-local exit is truly required,
                        Catch     Throw
                        Catch     Throw
there are the functions Catch and Throw, described in Section 9.5.

                                  Go  Return  Exit      Next
                                  Go  Return  Exit      Next
  The functions so restricted are Go, Return, Exit, and Next.  They must be
placed at top-level within the surrounding control structure to which  they
                   Prog         Return
                   Prog         Return
refer  (e.g.  the  Prog  which  Return  causes to be terminated), or nested
within only selected functions.  The functions in which they may be  nested
(to arbitrary depth) are:
     ProgN
     ProgN
   - ProgN (compound statement)
                Cond
                Cond
   - actions of Conds (if then else)
                Case
                Case
   - actions in Cases


 Go
 Go _____ __   ____ ________                           ____ ________  _____
(Go LABEL:id): None Returned                           open-compiled, fexpr

     Go                                            Prog
     Go                                            Prog
     Go alters the normal flow of control within a Prog function.  The
                          Prog
                          Prog
     next  statement of a Prog function to be evaluated is immediately
                             Go
                 _____       Go
     preceded by LABEL.   A  Go  may  appear  only  in  the  following
     situations:
Flow Of Control               7 February 1983                    PSL Manual
page 9.6                                                        section 9.3

                                   Prog
                                   Prog                _____
        a. At  the  top level of a Prog referring to a LABEL that also
                                                Prog
                                                Prog
           appears at the top level of the same Prog.
                              Cond
                              Cond
        b. As the action of a Cond item


                                                 Prog
                                                 Prog
              i. appearing on the top level of a Prog.
                                                   Cond
                                                   Cond
             ii. which appears as the action of a  Cond  item  to  any
                 level.


                                      ProgN
                                      ProgN
        c. As the last statement of a ProgN


                                                          Prog
                                                          Prog
              i. which  appears  at  the  top  level of a Prog or in a
                 ProgN                              Cond
                 ProgN                              Cond
                 ProgN appearing in the action of a Cond to any  level
                 subject to the restrictions of b.i, or b.ii.
                           ProgN                       Cond      ProgN
                           ProgN                       Cond      ProgN
             ii. within  a ProgN or as the action of a Cond in a ProgN
                 to any level subject  to  the  restrictions  of  b.i,
                 b.ii, and c.i.


                                                         Prog
         _____                                           Prog
     If  LABEL  does  not appear at the top level of the Prog in which
         Go
         Go
     the Go appears, an error occurs:

     ***** LABEL is not a label within the current scope

            Go
            Go
     If the Go has been placed in a position not defined by rules a-c,
     another error is detected:  

     ***** Illegal use of GO To LABEL 


 Return
 Return _ ____   ____ ________                          ____ ________  ____
(Return U:form): None Returned                          open-compiled, expr

              Prog  Return                                   Prog
              Prog  Return                                   Prog
     Within a Prog, Return terminates the evaluation  of  a  Prog  and
                                        Prog
              _                         Prog
     returns  U  as  the  value  of the Prog.  The restrictions on the
                  Return                      Go
                  Return                      Go
     placement of Return are exactly those of Go.  Improper  placement
        Return
        Return
     of Return results in the error:

     ***** Illegal use of RETURN 



9.4. Iteration
9.4. Iteration
9.4. Iteration


 While
 While _ ____  _ ____    ___                                          _____
(While E:form [S:form]): NIL                                          macro

     This is the most commonly used construct for indefinite iteration
                _                               _
     in  LISP.  E is evaluated; if non-NIL, the S's are evaluated from
                                                          _
     left to right and then the process is repeated.  If  E  evaluates
                 While               Exit
                 While               Exit
     to  NIL the While returns NIL.  Exit may be used to terminate the
PSL Manual                    7 February 1983               Flow Of Control
section 9.4                                                        page 9.7

     While                                                 Next
     While                                                 Next
     While  from  within  the body and to return a value.  Next may be
     used to terminate the current iteration.  In RLISP syntax this is
     While     Do
     While     Do
     While ... Do ... .  Note that in RLISP syntax there may be only a
                                  Do                             ProgN
                                  Do                             ProgN
     single expression after the  Do;  however,  it  may  be  a  ProgN
     delimited by <<...>>.  That is, 

        (While E S1 S2)

     should be written in RLISP as 

        While E do <<S1; S2>>;


 Repeat
 Repeat _ ____  _ ____    ___                                         _____
(Repeat E:form [S:form]): NIL                                         macro

          _                                            _
     The  S's  are  evaluated  left to right, and then E is evaluated.
                                                       Repeat
                                         _             Repeat
     This is repeated until the value of E is NIL, if  Repeat  returns
             Next       Exit
             Next       Exit                    _
     NIL.    Next  and  Exit may be used in the S's branch to the next
                    Repeat
                    Repeat
     iteration of a Repeat or to terminate one and possibly  return  a
               Go      Return
               Go      Return                   _
     value.    Go, and Return may appear in the S's.  The RLISP syntax
         Repeat    Repeat Until        While
         Repeat    Repeat Until        While
     for Repeat is Repeat Until.  Like While, RLISP syntax only allows
              _
     a single S, so

        (REPEAT E S1 S2)

     should be written in RLISP as 

        REPEAT << S1; S2 >> UNTIL E;

       [???  maybe do REPEAT S1 ... Sn E ???]
       [???  maybe do REPEAT S1 ... Sn E ???]
       [???  maybe do REPEAT S1 ... Sn E ???]


 Next
 Next    ____ ________                     ____ ________  __________  _____
(Next ): None Returned                     open-compiled, restricted, macro

     This  terminates  the  current  iteration  of  the  most  closely
                  While      Repeat
                  While      Repeat
     surrounding  While  or  Repeat,  and causes the next to commence.
     See the note in Section 9.3 about  the  lexical  restrictions  on
                                                               GO
                                                               GO
     placement  of  this  construct,  which  is  essentially a GO to a
     special label placed at the front of a loop construct.


 Exit
 Exit  _ ____    ____ ________              ____ ________ __________  _____
(Exit [U:form]): None Returned              open-compiled,restricted, macro

         _
     The U's are evaluated left to right, the most closely surrounding
     While    Repeat
     While    Repeat                                             _
     While or Repeat is terminated, and the value of  the  last  U  is
     returned.    With no arguments, NIL is returned.  See the note in
     Section 9.3 about the lexical restrictions on placement  of  this
                                       Return
                                       Return
     construct, which is essentially a Return.

  While       Repeat                          Prog  Next     Exit
  While       Repeat                          Prog  Next     Exit
  While  and  Repeat each macro expand into a Prog; Next and Exit are macro
                Go       Return                      Prog
                Go       Return                      Prog
expanded into a Go and a Return respectively to this Prog.   Thus  using  a
Next        Exit          Prog          While    Repeat
Next        Exit          Prog          While    Repeat
Next  or an Exit within a Prog within a While or Repeat will result only in
Flow Of Control               7 February 1983                    PSL Manual
page 9.8                                                        section 9.4

                        Prog
                        Prog
an exit of the internal Prog.  In RLISP be careful to use

    WHILE E DO << S1;...;EXIT(1);...;Sn>>

not 

    WHILE E DO BEGIN S1;...;EXIT(1);...;Sn;END;


9.4.1. For
9.4.1. For
9.4.1. For

           For
           For
  A simple For construct is available in the basic PSL system and RLISP; an
extended  form  can  obtained  by loading USEFUL. It is planned to make the
extended form the version available in the basic system, combining all  the
             FOR     ForEach                For
             FOR     ForEach                For
features  of FOR and ForEach. The basic PSL For provides only the (FROM ..)
                                                    ForEach
                                                    ForEach
iterator, and (DO ...) action clause, and uses the  ForEach  construct  for
some  of the (IN ...) and (ON ...)  iterators. Most PSL syntax users should
             For
             For
use the full For construct.


 For
 For  _ ____    ___                                                   _____
(For [S:form]): any                                                   macro

                      For
                      For
     The arguments to For are clauses; each clause is itself a list of
     a keyword and one or more arguments.  The clauses  may  introduce
     local  variables,  specify  return  values and when the iteration
     should cease,  have  side-effects,  and  so  on.    Before  going
     further, it is probably best to give some examples.

        (FOR (FROM I 1 10 2) (DO (PRINT I)))
                Prints the numbers 1 3 5 7 9

        (FOR (IN U '(A B C)) (DO (PRINT U)))
                Prints the letters A B C

        (FOR (ON U '(A B C)) (DO (PRINT U)))
                Prints the lists (A B C) (B C) and (C)

        Finally, the function
        (DE ZIP (X Y)
          (FOR (IN U X) (IN V Y)
                (COLLECT (LIST U V))))

     produces  a  list  of 2 element lists, each consisting of the the
     corresponding elements  of  the  three  lists  X,  Y  and  Z. For
     example, 

        (ZIP '(1 2 3 4) '(A B C) )

     produces 
PSL Manual                    7 February 1983               Flow Of Control
section 9.4                                                        page 9.9

        ((1 a)(2 b)(3 c))

     The iteration terminates as soon as one of the (IN ..) clauses is
     exhausted.

     Note  that  the  (IN  ...  ),  (ON  ...)  and  (FROM ...) clauses
     introduce local variables U, V or I, that are referred to in  the
     action clause.

     All  the  possible  clauses  are  described below.  The first few
     introduce iteration variables.  Most  of  these  also  give  some
     means of indicating when iteration should cease.  For example, if
                                     In
        ____                         In
     a  list being mapped over by an In clause is exhausted, iteration
                                                       For
                                                       For
     must cease.  If several such clauses are given in For expression,
     iteration ceases when one of the  clauses  indicates  it  should,
     whether or not the other clauses indicate that it should cease.


     (IN V1 V2)
                                                                  ____
               assigns the variable V1 successive elements of the list
               V2.

               This  may  take  an  additional,  optional  argument: a
               function to be applied  to  the  extracted  element  or
               sublist  before  it  is  assigned to the variable.  The
               following returns the sum of the  lengths  of  all  the
               elements of L. 

                 [???  Rather a kludge -- not sure why this is here.
                 [???  Rather a kludge -- not sure why this is here.
                 [???  Rather a kludge -- not sure why this is here.
                 Perhaps it should come out again. ???]
                 Perhaps it should come out again. ???]
                 Perhaps it should come out again. ???]

                  (DE LENGTHS (L)
                    (FOR (IN N L LENGTH)
                  (COLLECT (LIST N N)))

                  is the same as

                  (DE LENGTHS (L)
                    (FOR (IN N L)
                       (COLLECT
                        (LIST (LENGTH N) (LENGTH N))))
                  )

               but only calls LENGTH once. Using the (WITH ..) form to
               introduce a local LN may be clearer.

                  For example,
                  (SUMLENGTHS
                   '((1 2 3 4 5)(a b c)(x y)))
                  is
                  ((5 5) (3 3) (2 2))
Flow Of Control               7 February 1983                    PSL Manual
page 9.10                                                       section 9.4

     (ON V1 V2)
                                                  Cdr
                                                  Cdr         ____
               assigns the variable V1 successive Cdrs of the list V2.

     (FROM VAR INIT FINAL STEP)
               is  a  numeric iteration clause.  The variable is first
               assigned INIT, and then incremented by step until it is
               larger than FINAL.  INIT, FINAL, and STEP are optional.
               INIT and STEP both  default  to  1,  and  if  FINAL  is
               omitted  the  iteration continues until stopped by some
               other means.  To specify a  STEP  with  INIT  or  FINAL
               omitted,  or  a FINAL with INIT omitted, place NIL (the
               constant  --  it  cannot  be  an  expression)  in   the
               appropriate  slot  to  be  omitted.  FINAL and STEP are
               only evaluated once.

     (FOR VAR INIT NEXT)
               assigns the variable INIT first, and  subsequently  the
               value  of  the  expression  NEXT.  INIT and NEXT may be
               omitted.  Note that this is identical to  the  behavior
                                 Do
                                 Do
               of iterators in a Do.

     (WITH V1 V2 ... Vn)
               introduces  N locals, initialized to NIL.  In addition,
               each Vi may also be of the form (VAR  INIT),  in  which
               case it is initialized to INIT.

     (DO S1 S2 ... Sn)
               causes the Si's to be evaluated at each iteration.


     There  are  two clauses which allow arbitrary code to be executed
     before the first iteration, and after the last.


     (INITIALLY S1 S2 ... Sn)
               causes the Si's to be evaluated in the new  environment
               (i.e.  with  the  iteration  variables  bound  to their
               initial values) before the first iteration.

     (FINALLY S1 S2 ... Sn)
               causes  the  Si's  to  be  evaluated  just  before  the
               function returns.


     The  next  few  clauses  build  up  return types.  Except for the
     RETURNS/RETURNING  clause,  they  may  each  take  an  additional
     argument   which   specifies   that   instead  of  returning  the
     appropriate value, it is accumulated in the  specified  variable.
     For example, an unzipper might be defined as 
PSL Manual                    7 February 1983               Flow Of Control
section 9.4                                                       page 9.11

        (DE UNZIP (L)
          (FOR (IN U L) (WITH X Y)
            (COLLECT (FIRST U) X)
            (COLLECT (SECOND U) Y)
            (RETURNS (LIST X Y))))

                                               Zip
                                               Zip           ____
     This  is  essentially  the  opposite  of  Zip.  Given a list of 2
             ____                         ____                 ____
     element lists, it unzips them into 2 lists, and returns a list of
             ____
     those 2 lists.  For example, (unzip '((1 a)(2 b)(3  c)))  returns
     is ((1 2 3)(a b c)).


     (RETURNS EXP)
                                                                  For
                                                                  For
               causes the given expression to be the value of the For.
               Returning  is synonymous with returns.  It may be given
               additional arguments, in which case they are  evaluated
               in  order  and  the  value  of  the  last  is  returned
                         ProgN
                         ProgN
               (implicit ProgN).

     (COLLECT EXP)
               causes the successive values of the  expression  to  be
                                                       Append
                                  ____                 Append
               collected  into  a list.  Each value is Appended to the
                          ____
               end of the list.

     (UNION EXP)
                                                           ____
               is similar, but only adds an element to the list if  it
               is not equal to anything already there.

     (CONC EXP)
                                                  NConc
                                                  NConc
               causes the successive values to be NConc'd together.

     (JOIN EXP)
               causes them to be appended.

     (COUNT EXP)
               returns the number of times EXP was non-NIL.

     (SUM EXP), (PRODUCT EXP), (MAXIMIZE EXP), and (MINIMIZE EXP)
               do  the obvious.  Synonyms are summing, maximizing, and
               minimizing.

     (ALWAYS EXP)
               returns T if EXP is non-NIL on each iteration.  If  EXP
               is  ever  NIL,  the  loop  terminates  immediately,  no
               epilogue code, such as that introduced  by  finally  is
               run, and NIL is returned.

     (NEVER EXP)
               is equivalent to (ALWAYS (NOT EXP)).

     (WHILE EXP) and (UNTIL EXP)
               Explicit  tests  for  the  end of the loop may be given
Flow Of Control               7 February 1983                    PSL Manual
page 9.12                                                       section 9.4

               using  (WHILE EXP).  The loop terminates if EXP becomes
               NIL at the beginning of an iteration.   (UNTIL EXP)  is
                                                       While     Until
                                                       While     Until
               equivalent  to (WHILE (NOT EXP)).  Both While and Until
               may be given additional arguments; (WHILE E1 E2 ... En)
               is   equivalent   to   (WHILE (AND E1 E2 ... En))   and
               (UNTIL E1 E2 ... En)       is       equivalent       to
               (UNTIL (OR E1 E2 ... En)).

     (WHEN EXP)
               causes a jump to the next iteration if EXP is NIL.

     (UNLESS EXP)
               is equivalent to (WHEN (NOT EXP)).


  For
  For
  For is a general iteration construct similar in many  ways  to  the  LISP
                       Loop
                       Loop
Machine  and  MACLISP  Loop  construct,  and  the  earlier  Interlisp CLISP
                      For
                      For
iteration construct.  For,  however,  is  considerably  simpler,  far  more
                                      For
                                      For
"lispy", and somewhat less powerful.  For only works in LISP syntax.

  All  variable  binding/updating  still  precedes any tests or other code.
                   When    Unless
                   When    Unless
Also note that all When or Unless clauses apply to all action clauses,  not
                                                                   For
                                                                   For
just  subsequent  ones.    This  fixed  order  of evaluation makes For less
              Loop
              Loop
powerful than Loop, but also keeps it  considerably  simpler.    The  basic
order of evaluation is


   a. bind   variables  to  initial  values  (computed  in  the  outer
      environment)

                             Initially
                             Initially
   b. execute prologue (i.e. Initially clauses)

   c. while none of the termination conditions are satisfied:


                                              When       Unless
                                              When       Unless
         i. check conditionalization clauses (When  and  Unless),  and
            start next iteration if all are not satisfied.

        ii. perform body, collecting into variables as necessary

       iii. next iteration


   d. (after   a  termination  condition  is  satisfied)  execute  the
                      Finally
                      Finally
      epilogue (i.e.  Finally clauses)


For
For
For does all variable binding/updating in parallel.   There  is  a  similar
       For*
       For*
macro, For*, which does it sequentially.
PSL Manual                    7 February 1983               Flow Of Control
section 9.4                                                       page 9.13

 For!*
 For!*  _ ____    ___                                                 _____
(For!* [S:form]): any                                                 macro


9.4.2. Mapping Functions
9.4.2. Mapping Functions
9.4.2. Mapping Functions

  )

  The  mapping  functions  long familiar to LISP programmers are present in
                                   For
                                   For
PSL.  However, we believe that the For construct  described  above  or  the
        ForEach
        ForEach
simpler ForEach described below is generally more useful, since it obviates
the  usual necessity of constructing a lambda expression, and is often more
transparent.  Mapping functions  with  more  than  two  arguments  are  not
                                                ____
currently supported.  Note however that several lists may be iterated along
     For
     For
with For, and with considerably more generality.  For example:

   (Prog (I)
     (Setq I 0)
     (Return
       (Mapcar L
         (Function (Lambda (X)
                     (Progn
                       (Setq I (Plus I 1))
                       (Cons I X)))))))

may be expressed more transparently as 

   (For (IN X L) (FROM I 1) (COLLECT (CONS I X)))

Note  that  there  is  currently  no  RLISP  syntax  for  this,  but we are
contemplating something like:

   FOR X IN L AS I FROM 1 COLLECT I . X;

                         For
                         For
  To augment the simpler For loop present in  basic  PSL  and  support  the
      For Each
      For Each
RLISP For Each construct, the following list iterator has been provided:


 ForEach
 ForEach _ ___   ___                                                  _____
(ForEach U:any): any                                                  macro

           _____
           _____
           _____
           macro
           macro
     This  macro is essentially equivalent to the the map functions as
     follows:


     Possible forms are:
     Setting X to successive elements (CARs) of U:
     (FOREACH X IN U DO (FOO X))     --> (MAPC U 'FOO)
     (FOREACH X IN U COLLECT (FOO X))--> (MAPCAR U 'FOO)
     (FOREACH X IN U CONC (FOO X))   --> (MAPCAN U 'FOO)
     (FOREACH X IN U JOIN (FOO X))   --> (MAPCAN U 'FOO)

     Setting X to successive CDRs of U:
     (FOREACH X ON U DO (FOO X))     --> (MAP U 'FOO)
Flow Of Control               7 February 1983                    PSL Manual
page 9.14                                                       section 9.4

     (FOREACH X ON U COLLECT (FOO X))--> (MAPLIST U 'FOO)
     (FOREACH X ON U CONC (FOO X))   --> (MAPCON U 'FOO)
     (FOREACH X ON U JOIN (FOO X))   --> (MAPCON U 'FOO)


     The RLISP syntax is quite simple:

        FOR EACH x IN y DO z;
        FOR EACH x ON y COLLECT z;
        etc.

        Note that FOR EACH may be written as FOREACH


 Map
 Map _ ____ __ ________   ___                                          ____
(Map X:list FN:function): NIL                                          expr

                                  Cdr
              __                  Cdr             _
     Applies  FN  to  successive  Cdr segments of X.  NIL is returned.
     This is equivalent to:   

        (FOREACH u ON x DO (FN u))


 MapC
 MapC _ ____ __ ________   ___                                         ____
(MapC X:list FN:function): NIL                                         expr

                                 Car
     __                          Car               ____  _
     FN is applied to successive Car segments  of  list  X.    NIL  is
     returned.  This is equivalent to:   

        (FOREACH u IN x DO (FN u))


 MapCan
 MapCan _ ____ __ ________   ____                                      ____
(MapCan X:list FN:function): list                                      expr

                                                     Car
                    ____    __                       Car             _
     A concatenated list of FN applied to successive Car elements of X
     is returned.  This is equivalent to:   

        (FOREACH u IN x CONC (FN u))


 MapCar
 MapCar _ ____ __ ________   ____                                      ____
(MapCar X:list FN:function): list                                      expr

                                   ____                             __
     Returned  is  a  constructed  list,  the elements of which are FN
                     Car
                     Car    ____ _
     applied to each Car of list X.  This is equivalent to:

        (FOREACH u IN x COLLECT (FN u))


 MapCon
 MapCon _ ____ __ ________   ____                                      ____
(MapCon X:list FN:function): list                                      expr

                                                                   Cdr
                                ____    __                         Cdr
     Returned is a concatenated list of FN applied to  successive  Cdr
                 _
     segments of X.  This is equivalent to:
PSL Manual                    7 February 1983               Flow Of Control
section 9.4                                                       page 9.15

        (FOREACH u ON x CONC (FN u))


 MapList
 MapList _ ____ __ ________   ____                                     ____
(MapList X:list FN:function): list                                     expr

                            ____                            __
     Returns  a constructed list, the elements of which are FN applied
                   Cdr
                   Cdr             _
     to successive Cdr segments of X.  This is equivalent to:

        (FOREACH u ON x COLLECT (FN u))


9.4.3. Do
9.4.3. Do
9.4.3. Do

                    Do     Let
                    Do     Let
  The MACLISP style Do and Let are now partially implemented in the  USEFUL
module.


 Do
 Do _ ____ _ ____  _ ____    ___                                      _____
(Do A:list B:list [S:form]): any                                      macro

          Do
          Do
     The  Do macro is a general iteration construct similar to that of
     LISPM and friends.  However, it does differ in some  details;  in
                                                                Do
                                                                Do
     particular  it  is  not  compatible  with  the  "old style Do" of
     MACLISP, nor does it support the "no end test  means  once  only"
                  Do
                  Do
     convention.  Do has the form

        (DO (I1 I2 ... In)
            (TEST R1 R2 ... Rk)
            S1
            S2
            ...
            Sm)

     in which there may be zero or more I's, R's, and S's.  In general
     the I's have the form 

        (var init step)

                        Do
                        Do
     On  entry  to  the Do form, all the inits are evaluated, then the
     variables are bound to their  respective  inits.    The  test  is
     evaluated,  and if non-NIL the form evaluates the R's and returns
     the value of the last one.  If none are supplied it returns  NIL.
     If the test evaluates to NIL the S's are evaluated, the variables
     are  assigned  the  values of their respective steps in parallel,
     and the test evaluated again.   This  iteration  continues  until
     test  evaluates  to  a  non-NIL  value.   Note that the inits are
     evaluated in the surrounding environment,  while  the  steps  are
                                                          Do
                                                          Do
     evaluated  in  the new environment.  The body of the Do (the S's)
          Prog                             Go
          Prog                             Go
     is a Prog, and may contain labels and Go's, though use of this is
                                                          Return
                                                          Return
     discouraged.  It may be changed at a later  date.    Return  used
                Do
                Do
     within  a  Do  returns immediately without evaluating the test or
     exit forms (R's).
Flow Of Control               7 February 1983                    PSL Manual
page 9.16                                                       section 9.4

     There are alternative forms for the I's:  If the step is omitted,
     the  variable's  value  is  left unchanged.  If both the init and
                                        __
     step are omitted or if the I is an id, it is initialized  to  NIL
     and  left unchanged.  This is particularly useful for introducing
                               SetQ
                               SetQ
     dummy variables which are SetQ'd inside the body.


 Do!*
 Do!* _ ____ _ ____  _ ____    ___                                    _____
(Do!* A:list B:list [C:form]): any                                    macro

     Do!*         Do
     Do!*         Do
     Do!* is like Do, except the variable bindings and  updatings  are
     done sequentially instead of in parallel.


 Do-Loop
 Do-Loop _ ____ _ ____ _ ____  _ ____    ___                          _____
(Do-Loop A:list B:list C:list [S:form]): any                          macro

     Do-Loop          Do
     Do-Loop          Do
     Do-Loop  is like Do, except that it takes an additional argument,
     a prologue.  The general form is 

        (DO-LOOP (I1 I2 ... In)
            (P1 P2 ... Pj)
            (TEST R1 R2 ... Rk)
            S1
            S2
            ...
            Sm)

                                                     Do
                                                     Do
     This is executed just like  the  corresponding  Do,  except  that
     after  the  bindings are established and initial values assigned,
     but before the test is first executed the P's are  evaluated,  in
     order.    Note  that  the  P's  are  all  evaluated  exactly once
     (assuming that none of the P's err out, or otherwise throw  to  a
     surrounding context).


 Do-Loop!*
 Do-Loop!* _ ____ _ ____ _ ____  _ ____     ___                       _____
(Do-Loop!* A:list B:list C:list [S:form_]): any                       macro

     Do-Loop!*
     Do-Loop!*
     Do-Loop!*  does  the  variable  bindings and undates sequentially
     instead of in parallel.


 Let
 Let _ ____  _ ____    ___                                            _____
(Let A:list [B:form]): any                                            macro

     Let
     Let
     Let is a macro giving a more perspicuous form for writing  lambda
     expressions.  The basic form is

     (LET ((V1 I1) (V2 I2) ...(Vn In)) S1 S2 ...  Sn)

     The I's are evaluated (in an unspecified order), and then the V's
     are  bound  to  these values, the S's evaluated, and the value of
     the last is returned.  Note that the I's  are  evaluated  in  the
     outer environment before the V's are bound.
PSL Manual                    7 February 1983               Flow Of Control
section 9.4                                                       page 9.17

                __
     Note:  the id LET conflicts with a similar construct in RLISP and
     REDUCE


 Let!*
 Let!* _ ____  _ ____    ___                                          _____
(Let!* A:list [B:form]): any                                          macro

     Let!*              Let
     Let!*              Let
     Let!* is just like Let  except  that  it  makes  the  assignments
     sequentially.    That  is,  the  first binding is made before the
     value for the second one is computed.



9.5. Non-Local Exits
9.5. Non-Local Exits
9.5. Non-Local Exits

  One occasionally wishes to discontinue a computation in which the lexical
                             Return
                             Return
restrictions on placement of Return are too  restrictive.    The  non-local
                  Catch      Throw
                  Catch      Throw
exit  constructs  Catch  and Throw exist for these cases.  They should not,
however, be used indiscriminately.  The lexical restrictions on their  more
local  counterparts  ensure  that the flow of control can be ascertained by
                                         Catch     Throw
                                         Catch     Throw
looking at a single piece of code.  With Catch and Throw,  control  may  be
passed  to  and  from  totally  unrelated  pieces  of  code.    Under  some
conditions, these functions are invaluable.  Under others, they  can  wreak
havoc.


 Catch
 Catch ___ __  ____ ____    ___                        ____ ________  _____
(Catch TAG:id [FORM:form]): any                        Open-Compiled, fexpr

     Catch                                      Eval
     Catch                  ___                 Eval        ____
     Catch  evaluates  the  TAG  and then calls Eval on the FORMs in a
                                                        Throw
                                                        Throw ___ ___
     protected environment.  If during this evaluation (Throw TAG VAL)
             Catch                                 Throw
             Catch                     ___         Throw
     occurs, Catch immediately returns VAL.  If no Throw  occurs,  the
                          ____
     value  of  the  last FORM is returned.  Note that in general only
     Throw                                 Throw                    Eq
     Throw                ___              Throw        ___         Eq
     Throws with the same TAG are caught.  Throws whose TAG is not  Eq
                Catch                                  Catch
                Catch                                  Catch       ___
     to that of Catch are passed on out to surrounding Catches.  A TAG
                                     Catch
                                     Catch
     of  NIL, however, is special.  (Catch NIL @var[form)] catches any
     Throw
     Throw
     Throw.


               __________                                            ______
THROWSIGNAL!* [Initially: NIL]                                       global


            __________                                               ______
THROWTAG!* [Initially: NIL]                                          global

     The  FLUID  variables  THROWSIGNAL!*  and   THROWTAG!*   may   be
                                                             Catch
                                                             Catch
     interrogated to find out if the most recently evaluated Catch was
     Throw                                       Throw
     Throw                                       Throw
     Thrown  to,  and what tag was passed to the Throw.  THROWSIGNAL!*
        Set                                Catch
        Set                                Catch
     is Set to NIL upon normal exit from a Catch, and to T upon normal
               Throw                 Set
               Throw                 Set
     exit from Throw.  THROWTAG!* is Set to the first argument  passed
            Throw                    Throw     Eval
            Throw                    Throw     Eval ____
     to the Throw.  (Mark a place to Throw to, Eval FORM.)
Flow Of Control               7 February 1983                    PSL Manual
page 9.18                                                       section 9.5

 Throw
 Throw ___ __  ___ ___   ____ ________                                 ____
(Throw TAG:id  VAL:any): None Returned                                 expr

                                                      Catch         Eq
                                                      Catch         Eq
     This  passes  control to the closest surrounding Catch with an Eq
                                                     Catch
             ___                                     Catch
     or null TAG.  If there is no such  surrounding  Catch  it  is  an
                                       _____
                                       _____
                                       _____
                                       Throw
            __  ___  _______  __  ___  Throw
     error  in  the  context  of  the  Throw.  That is, control is not
     Throw                                        Error
     Throw                                        Error
     Thrown to the top level before the call  on  Error.    (Non-local
     Goto
     Goto
     Goto.)

  Some examples:

   In LISP syntax, with

   (DE DOIT (x)
    (COND ((EQN x 1) 100)
          (T (THROW 'FOO 200))))

   (CATCH 'FOO (DOIT 1) (PRINT "NOPE") 0)
           will continue and execute the PRINT statement
           and return 0
   while

   (CATCH 'FOO (DOIT 2) (PRINT "NOPE") 0)

   will of course THROW, returning 200 and not executing
   the last forms.


  A  common  problem  people  encounter  is  how  to  pass arguments and/or
                                  CATCH
                                  CATCH
computed functions or tags  into  CATCH  for  protected  evaluation.    The
following  examples should illustrate. Note that TAG is quoted, since it is
evaluated before use in CATCH and THROW.

   In LISP syntax:

   (DE PASS-ARGS(X1 X2)
      (CATCH 'FOO (FEE (PLUS2 X1 X2) (DIFFERENCE X1 X2))))

  This is simple, because CATCH compiles open.  No  FLUID  declarations  or
                                                                      Apply
                                                                      Apply
LIST building is needed, as in previous versions of PSL.  An explicit Apply
must be used for a function argument; usually, the APPLY will compile open,
with no overhead:

   In LISP syntax:

   (DE PASS-FN(X1 FN)
      (CATCH 'FOO (APPLY FN (LIST X1))))

                                                            Catch     Throw
                                                            Catch     Throw
  The  following  MACROs  are provided to aid in the use of Catch and Throw
with a NIL tag, by examining the THROWSIGNAL!* and THROWTAG!*:
PSL Manual                    7 February 1983               Flow Of Control
section 9.5                                                       page 9.19

 Catch!-All
 Catch!-All __ ________  ____ ____    ___                             _____
(Catch!-All FN:function [FORM:form]): any                             macro

                     Catch
                     Catch
     This  issues a (Catch NIL ...); if a Throw was actually done, the
              __
     function FN is applied to the two arguments  THROWTAG!*  and  the
                            throw                                Throw
                            throw                                Throw
     value  returned by the throw.  Thus FN is applied only if a Throw
     was executed.


 Unwind!-All
 Unwind!-All __ ________  ____ ____    ___                            _____
(Unwind!-All FN:function [FORM:form]): any                            macro

                    Catch
                    Catch                        __
     This issues a (Catch NIL ...). The function FN is always  called,
     and  applied  to  the  two  arguments  THROWTAG!*  and  the value
                     throw        Throw
                     throw        Throw               __
     returned by the throw. If no Throw was done then FN is called  on
     NIL and the value returned.


 Unwind!-Protect
 Unwind!-Protect _ ____  _ ____    ___                                _____
(Unwind!-Protect F:form [C:form]): any                                macro

                                                  _
     The idea is to execute the "protected" form, F, and then run some
                      _
     "clean-up" forms C even if a Throw (or Error) occurred during the
                                     Catch
                   _                 Catch
     evaluation of F. This issues a (Catch NIL ...), the cleanup forms
     are  then  run,  and  finally  either the value is returned if no
     Throw occurred, or the Throw is "re-thrown" to the same tag.

     A common example is to ensure a file be closed after  processing,
     even if an error or throw occurred:

        (SETQ chan (OPEN file ....))
        (UNWIND-PROTECT (process-file)
                        (CLOSE chan))

  Note:  Certain special tags are used in the PSL system, and should not be
interfered with casually:


                  Error     ErrorSet
                  Error     ErrorSet
!$ERROR!$ Used by Error and ErrorSet which  are  implemented  in  terms  of
          Catch     Throw
          Catch     Throw
          Catch and Throw, see Chapter 14).

!$UNWIND!-PROTECT!$
          A  special  TAG  placed  to  ensure  that ALL throws pause at the
          UNWIND-PROTECT "mark".

                                                  PROG   GO      RETURN
                                                  PROG   GO      RETURN
!$PROG!$  Used to communicate between interpreted PROGs, GOs and RETURNs.
