Saturday Jan 27,1979 LQ+7D.1H.40M.31S. LISP 1785 / COMPLR 867 -JONL- 1) EVAL-WHEN - - a new fsubr, like DECLARE but much more general 2) DEFUN permits LISP-Machine like syntax, and LET-destructuring of arguments. 3) New AUTOLOADable MACROs: LET, LET*, DESETQ; and DEFMACRO, MACRO, DEFUN& Functions MACROEXPAND and MACROEXPAND-1, defined as on LISPM, are available 4) Better error checking in *RSET mode for functions that cdr down lists: LAST now gets the last node of a non-atomic s-expression, or () for (). 5) "MACLISP" is now on the feature list, to help distinguish from LISPM. 6) COMPLR has some new switches and global variables - EXPAND-OUT-MACROS etc. 7) SUSPEND - review of meanings of arguments 8) Under the ITS operating system, a JCL line with only a <space> means don't use any INIT file, even if the connected directory has one. This may be extended to the TOPS versions also. ____________________________________________________________________________ 1) EVAL-WHEN - - a new fsubr, like DECLARE but much more general (EVAL-WHEN (<id1> <id2> ... <idn>) <foo1> <foo2> . . . <foon>) will cause the evaluation of the various <fooi> only if the "evaluator" matches one of the indicators in the first list; these indicators <idi> may be among EVAL, COMPILE, or LOAD, which respectively trigger EVAL - a normal, read-eval-print loop COMPILE - the "maklap" processor, which compiles files LOAD - "fasload" (which only processes compiler output) (EVAL-WHEN (COMPILE) (SAY THIS)) is entirely equivalent to (DECLARE (SAY THIS)) (EVAL-WHEN (EVAL LOAD) (RUN THAT)) is generally equivalent to (RUN THAT) (EVAL-WHEN (LOAD) (PRINT '|Loading Compiled version of Foo|)) will cause the print request to appear only in the compiled FASL file, and be run at load time. (or LAP file if you don't assemble). (EVAL-WHEN (EVAL COMPILE LOAD) (SETSYNTAX '/% 'MACRO 'FUNNY-FUN)) causes evaluation in all environments, which is often what one wants with macro characters. 2) DEFUN permits LISP-Machine like syntax, and LET-destructuring of arguments. DEFUN automatically becomes DEFUN& if "&" keywords occur in the dummy argument list, or any dummy argument is not a symbol; see 3b below. 3) New AUTOLOADable MACROs: LET, LET*, DESETQ; and DEFMACRO, MACRO, DEFUN& Functions MACROEXPAND and MACROEXPAND-1, defined as on LISPM, are available from the file supporting DEFUN&, but they do not have autoload properties. LET, LET*, and DESETQ are on the same file LISP;LET FASL DEFMACRO, MACRO, and DEFUN& are on the file LISP;DEFMAC FASL In the BNF descriptions below, "{...|...}" denotes precisely one of the alternatives between the brackets and separated by vertical-bars; "{...}*" means zero or more occurances of the alternatives, "{...}+" means one or more occurances. 3a) LET, LET*, and DESETQ Following the many user definitions of a macro LET, we now have an autoload property for LET, and a definitions of it which is fairly intuitive: (LET ((A <e1>) (B <E2>) ... (C <en>)) <computate>) macro-expands into ((LAMBDA (A B ... C) <computate> ) <e1> <e2> ... <en>) In certain arcane instances, one wants a sequential binding, rather than the parallel binding that occurs for a multiple-variable LAMBDA; thus, LET* may be used: (LET* ((A <e1>) (B <E2>) ... (C <en>)) <computate>) macro-expands into ((LAMBDA (A) ((LAMBDA (B) ... ((LAMBDA (C) <computate> ) <en>) ... ) <e2>) <en>) In all other respect, however, LET* is similar to LET. One especially useful feature which the MACLISP macro for LET has is that of "pattern decomposition": a general data pattern may be used in each place where a variable is expected; and for each combination of data-accessing functions which access a non-null symbol in the data pattern, there is set up a binding between that symbol and the same data-accessing path applied to the "argument" expression (that is, one of the <ei>). Thus nullist in a pattern means "ignore". A simple example should suffice, but also a BNF description is given. (LET ( ((A . B) <e1>) ((() C () D) <e2>) (TEMP1) TEMP2 ) <computate>) expands into something that operates like ((LAMBDA (G0001 G0002 A B C D TEMP1 TEMP2) (SETQ A (CAR G0001)) (SETQ B (CDR G0001)) (SETQ C (CADR G0002)) (SETQ D (CADDDR G0002)) <computate>) <e1> <e2> () () () () () () ) Just exactly what code comes out of the LET macro depends on many things, but the intent is to "decompose" the argument, according to the structure of the pattern of variables, and bind the variables correspondingly. DESETQ is similar, but there is no "binding" involved - only "set"ing. For example, (DESETQ (A . B) (MUMBLIFY)) might become ((LAMBDA (G0001) (SETQ A (CAR G0001) B (CDR G0001))) (MUMBLIFY)) When compiled, the extra variable G0001 may not cause any noticeable slowdown in the running of such code, but if the item being destructured is denoted by a variable, then there is no new LAMBDA: (DESETQ (() C () D) XVAR) might expand into (SETQ C (CADR XVAR) D (CADDDR XVAR)) A given instance of LET or DESETQ usage will be "DISPLACED" or not depending on the value of the variable DEFMACRO-DISPLACE-CALL; See 3c below for more information about the use of this flag. In point of fact, LET is continually being extended to know about structures other than lists; thus in NIL, one may destructure thru VECTORs also, and thru a "record" created by the structure package DEFVST (currently on LIBDOC and LIBLSP). But leaving aside these more arcane data structure for now, a BNF description would be ( LET ( { <symbol> | ( <pattern> <computation> ) }* ) { <s-exp> }* ) where a "<pattern>" may be a symbol, or the nullist, or any list (or "vector", or "defvst") structure. Also: ( DESETQ <pattern> <computation> ) 3b) DEFUN&, for maclisp compatibility with the extended DEFUN syntax of the LISPMachine, using "&OPTIONAL" and "&REST" Also, note that if DEFUN notices the occurance of any of the keywords &OPTIONAL, &REST, or &AUX in the defining arglist, the the form is automatically turned into a DEFUN& (which may have to be autoloaded). This way, it will appear that MACLISP supports the extended syntax. Let an "<arglist>" be defined by BNF as follows: ( {<pattern>}* { &OPTIONAL { <symbol> | ( <pattern> <s-exp> ) }* } { &REST <symbol> } { &AUX { <symbol> | ( <pattern> <s-exp> ) }* } ) Then the extended DEFUN syntax is defined by ( DEFUN { <symbol> | (<symbol> <symbol>) | (<symbol> <symbol> <symbol>) }+ { EXPR | FEXPR | MACRO | | } { <symbol> | () | <arglist> } { ( DECLARE { <s-exp> }* ) | | } { <s-exp> }* ) Note that this allow pattern decomposition at each argument position of a function definition; if a single symbol, say <sym> occurs in the optional list, it is treated as if it were of the form "(<sym> () )" - this way there is no ambiguity caused by the permission of <pattern>s in the optional list, for the use of such must be in the default-value-supplied form. Also, the order of evaluation of the default values for optional arguments, and of the values for the auxillary variables, is strictly left-to-right, **after** all the non-optional argument bindings have been made. Here is an example with a lot of "bells-and-whistles" just for illustrative purposes: (DEFUN FOO ( (() NAME VARLIST . BODY) KIND &OPTIONAL (PS-FLAG (AND (EQ (CAAR BODY) 'DECLARE))) ((DNAM . DLST) (AND PS-FLAG (CADAR BODY))) &REST W &AUX (N (COND (PS-FLAG 5) (6))) ) (WORK-IT-OUT ...)) Thus FOO requires at least two arguments; and two more will be further bound, one into PS-FLAG, and the other destructured into (DNAM . DLST) 3c) DEFMACRO, MACRO -- macro-producing macros, compatible with LISPM. Three flags are noticed during instances of the macro expansions: DEFMACRO-CHECK-ARGS (default = T) DEFMACRO-DISPLACE-CALL (default = T) DEFMACRO-FOR-COMPILING (default = T) The first flag if non-null, produces a macro which checks each instance of usage for compatible numbers of "arguments"; since this checking takes time, it may not be desirable in all circumstances. The second if non-null, produces a macro which calls DISPLACE in order to displace out the original macro call. The macros MACRO-DISPLACE and DEFMACRO-DISPLACE exist, just as in the LISPM, which do not pay attention to this flag, but rather always yield a product which uses DISPLACE. The third determines which of the two macro-defining forms will be used: (DEFUN foo MACRO ...) or (DEFUN (foo MACRO) ...) If non-null, the latter will be used so that the macro will be compiled by the compiler (whereas the former format is intended primarily for macros used interpretively, or as compilation aids; see 5b below. DEFMACRO admits a "bound-variable-list" that is reminiscent of the standard argument-list processing: ( {<pattern>}* {&OPTIONAL {<symbol> | (<pattern> <default.evaluation>) }+ } {&REST <symbol>} ) As with DEFUN&, a single symbol, say <sym>, in the &optional list is treated as if it were of the form "(<sym> () )", for purposes of default initializations. Examples: (MACRO ERRBRK (X) (COND ((EQ (CADR X) 'BARF) '(ERR)) (`(PROG2 (PRINC ',(cadr x)) (BREAK ERROR))))) (DEFMACRO ERRBRK (MSG &OPTIONAL (BKTYPE 'ERROR)) (COND ((EQ (CADR X) 'BARF) '(ERR)) (`(PROG2 (PRINC ',msg) (BREAK ,bktype))))) 4) Better error checking in *RSET mode for functions that cdr down lists: LAST now gets the last node of a non-atomic s-expression, or () for (). In *RSET mode, the time is taken to check that no attempt is made to take the cdr of a non-null atom in the functions NTH, NTHCDR, APPEND, NCONC, REVERSE, NREVERSE, NRECONC, ASSQ, MEMQ, DELQ Regardless of the setting of *RSET, the following functions will not cdr through a non-null atom: LAST, MEMBER, ASSOC, DELETE, all MAP series. [In LISP versions prior to about 1783, LAST had the bug that it would begin cdr'ing down the plist of any symbol at the termination of a non-standard list - try (LAST '(A . CAR))]. Note however, if any of the MAP series gets expanded into a DO loop by the compiler, the endtest will be replaced by NULL rather than ATOM. 5) "MACLISP" is now on the feature list, to help distinguish from LISPM. (STATUS FEATURE LISPM) is non-null for the LISP machine (STATUS FEATURE MACLISP) is non-null for all PDP10 and MULTICS MACLISPs (STATUS FEATURE NIL) is non-null for any real or simulated NIL. 6) COMPLR has some new switches and global variables - EXPAND-OUT-MACROS etc. 6a) new switch - H for variable EXPAND-OUT-MACROS Toplevel forms which are not functions to be compiled (or other wise specially treated by MAKLAP) could be fully macro-expanded before being output to the FASL file. Normal setting is non-null meaning to do this expansion. 6b) repeat of meaning of the M switch - variable MACROS MAKLAP will not cause the compilation of a form like (DEFUN <foo> MACRO (<var>) ...) when it is processing a file, for it assumes that this macro is only for aid during compilation. If MACROS is non-null, it will also output an expr form for such a macro into the FASL file. Remember that if the definition is like (DEFUN (<foo> MACRO) (<var>) ...), then the compiled version of the macro will always be output. In either case, COMPLR remembers the expr definition for use during the subsequent parts of the file. 6c) new variable - MAKLAP-DEFAULTF-STYLE The command line read maklap usually consists of two file specs separater by a left-arrow (underscore in new ascii); the filling in of the unspecified components of a file spec can be done either from the accumulated left-to-right mergeing, or begin separately for input and output file specs. MIDAS style is the former, and the value of this new variable either is MIDAS or (). 6d) when making up, can set feature NO-EXTRA-OBARRAY (SSTATUS FEATURE NO-EXTRA-OBARRAY) will permit CCLOAD to make up a compiler without the COBARRAY/CREADTABLE which separates user environment from compiler environment. If saving about 1.5K or so words means that much to you, and taking a chance means very little . . . 7) SUSPEND - review of meanings of arguments [Original information in the LISP NEWS file, under dates 5/22/74 JAN 13,1978 June 14,1978 ] If no arguments are given, then a return to monitor is preceeded by the message ";$Suspended$" (in ITS, it is ":Suspended", and those are alt-modes rather than dollar-signs). First arg - string for printing to exec; null; or (on ITS) small fixnum. Ordinarily, when the suspended LISP returns to the monitor, it will print the message ";$Suspended$", but a non-null symbol will be printed instead; null means continue immediately, possibly after dumping out into the file specified by the second argument. For ITS system, the message printed out will be executed by DDT, just like a string to VALRET; if the argument is a fixnum, it will be taken as the value to put in the right half of a .BREAK 16,. Second arg - file name in which to dump the pure parts of the system For ITS system, the job is PDUMPd, with an "indirect" symbol table; the pages shared with the system-dumped TS LISP are not dumped if (STATUS FLUSH) is non-null. Since a LISP tries to share its read-only pages with the system-dumped TS LISP, the only reason for allowing them to be copied out into the dump'd file when SUSPENDing is the fear that the system-dumped TS LISP may inadvertently disappear off the file system. For TOPS-10 systems (and SAIL), the high segment of a two-segment job is dumped into this file; one must still type a SSAVE (or or SAVE) at the monitor in order to dump the low segment. But if (STATUS FLUSH) is non-null, then no dumping of the high segment occurs, and it is flushed before returning to the monitor, so that when the dumped low segment is re-activated, it will try to retrieve the high segment associated with the original LISP.SHR file. Caution! As of Jan 1979, there may still be bugs in the non-its version of SUSPEND. 8) Under the ITS operating system, a JCL line with only a <space> means don't use any INIT file, even if the connected directory has one. This may be extended to the TOPS versions also.