Saturday Feb 07,1981 NM+3D.15H.34M.49S. LISP 2071 / COMPLR 1094 -- JonL -- 1) Multiple-value capability implemented thru some autoloadable things: New AUTOLOADable macros and capabilities from MLMAC: MULTIPLE-VALUE, VALUES, MULTIPLE-VALUE-BIND Autoloading SUBRs from file MLSUB: MULTIPLE-VALUE-LIST, VALUES-LIST, and SI:CHECK-MULTIPLICITIES Non-autoloading macros available in MLMAC: MULTIPLE-VALUE-RETURN and RETURN-LIST Reminder: MULTIPLE-VALUE is essentially the same as MSETQ-CALL of previous notes. The names MSETQ-CALL and MSETQ-RETURN will be superseded by the LISPM names; however macros to convert them will be provided in the UMLMAC file (Utility MacLisp MACros). [more exposition below] 2) Additional, new "out-of-core" SUBRs and MACROs: Two LSUBRs "<=" and ">=", of 2 or more args are autoloadable from MLSUB file SOURCE-TRANS properties are set up, in the MLMAC file, for LOGAND, LOGIOR, LOGXOR, LOGNOT, FIXNUMP, FLONUMP, EVENP, <=, >=, <, and >. (see item 4 below for "SOURCE-TRANS"), and these are used to generate some other SUBRs in the MLSUB file: LOGAND, LOGIOR, LOGXOR, LOGNOT, LISTP, FIXNUMP, FLONUMP, and EVENP. Non-autoloading macro available in DEFMAC: DEFUNP Non-autoload versions of FMAKUNBOUND, FSYMEVAL, and FSET are in FUNCEL file. [more exposition below] 3) Default value for DEFUN&-CHECK-ARGS is now (), and whenever &OPTIONAL or &REST args are specified, the "args property" of the symbol will be set. [more exposition below] DEFUN&-CHECK-ARGS is the variable which says whether or not there should be code in the function itself to do number-of-args checking. The interpreter, and "UUO" handler, when in *RSET mode, will check the number of arguments passed to a LSUBR/SUBR against the "args property", which is retrieved and set by the ARGS function. 4) SOURCE-TRANS properties for COMPLR act almost like LISPM "optimizers". [more exposition below] 5) FILE-EXIT-FUNCTIONS is a new global variable which is lambda-bound to the value of FILE-EXIT-FUNCTIONS-DEFAULT by LOAD and FASLOAD. It holds a list of functions of 1 arg to be run at end of loading. [more exposition below] 6) DEFSFA, a macro for defining macros to make SFA usage easier, is now defined in the EXTMAC file (along with DEFCLASS* and DEFMETHOD*) see the documentation file SFA.DOC (on ITS system -- .INFO.;LISP SFA) for full information. _______________________________________________________________________ 1) Multiple-value capability implemented thru some autoloadable things: New AUTOLOADable macros and capabilities from MLMAC: MULTIPLE-VALUE, VALUES, MULTIPLE-VALUE-BIND Autoloading SUBRs from file MLSUB: MULTIPLE-VALUE-LIST, VALUES-LIST, and SI:CHECK-MULTIPLICITIES Non-autoloading macros available in MLMAC: MULTIPLE-VALUE-RETURN and RETURN-LIST Reminder: MULTIPLE-VALUE is essentially the same as MSETQ-CALL of previous notes. The names MSETQ-CALL and MSETQ-RETURN will be supersede by the LISPM names; however macros to convert them will be provided in the UMLMAC file (Utility MacLisp MACros). Frequently, it is convenient to think of a function as returning several values; in LISP, one often just constructed a list of the several item, and the calling function would "destructure" that list. The basic special forms MULTIPLE-VALUE and VALUES are provided to indicate respectively a function call which is expected to return (possibly) multiple values, and a function exit which does provide (possibly) multiple values. Cooperation is achieved through a "return-values vector", which in MacLISP is just a collection of several special variables. MULTIPLE-VALUE is somewhat like SETQ in that the multiple-values returned by the call will be set into some variables; e.g., (MULTIPLE-VALUE (AVERAGE MAX STANDARD-DEVIATION) (STATISTICS-GATHERER x1 y1 ...)) might set up three values in the variables AVERAGE, MAX, and STANDARD-DEVIATION, but without requiring an intermediate list of results. Similarly, (MULTIPLE-VALUE-BIND (AVERAGE MAX STANDARD-DEVIATION) (STATISTICS-GATHERER x1 y1 ...) (do-something ...) ... (do-last-thing ...)) provides a lambda-binding, rather than a setting, of the variables, over the enclosed scope. Also, for example, the routine STATISTICS-GATHERER might look like (DEFUN STATISTICS-GATHERER (a1 a2 ...) ... ;lotta work here! (VALUES (//$ SUM N) HIGHEST (COMPUTE-SD))) The value of the form (MULTIPLE-VALUE (X ...) ...) is the thing which got set to X; since destructuring works with MULTIPLE-VALUE, then (MULTIPLE-VALUE (() Y ...) ...) returns the thing which would have been set to the first variable, had it not been (). MSETQ-CALL and MSETQ-RETURN are being superseded by the LISPM names, which are now essentially equivalent; minor differences are noted by an occurrence of **** in the documentation here below. 1a) MULTIPLE-VALUE, in MacLISP, macroexpands into code to setq the requested variables to the multiple values returned by a function call. E.g. (MULTIPLE-VALUE (FORM EX?) (MACROEXPAND-1*M FORM)) calls a macroexpander which returns two values -- the first is the possibly expanded form, and the second is a flag saying whether or not any expansion really happened. If there aren't enough returned values to set all the indicated variables, the default action of the MacLISP facility is to pad out with ()'s (same as on LISPM); however, **** if the global variable SI:CHECK-MULTIPLICITIES is set to CERROR, an error will be signalled instead. See the discussion under item 4 below. 1b) VALUES is a new LISPM special form, and in NIL/MacLISP it is essentially the same thing as MSETQ-RETURN was; its basic action is to set up a "return-values vector"; typical usage would be to call VALUES as the last form in a lambda-expression. Example: (DEFUN TWIST (X Y) (COND ((AND (NUMBERP X) (NUMBERP Y)) (VALUES 'T (LESSP X Y))) ('T (SETQ X (TO-STRING X) Y (TO-STRING Y)) (VALUES () (ALPHALESSP X Y))))) 1c) MULTIPLE-VALUE-LIST constructs a list of all the (possibly multiple) values returned by the evaluated sub-form. Format of usage is like (MULTIPLE-VALUE-LIST (<fun> ...)) where <fun> should return some (possibly multiple) values. 1d) RETURN in MacLISP still admits only one argument **** -- in order to do a RETURN with multiple arguments, do (RETURN (VALUES first second ...)) MULTIPLE-VALUE-RETURN is primitive on the LISPM, but is macro expanded in MacLISP to use merely RETURN. Currently, RETURN (but not MULTIPLE-VALUE-RETURN) is primitive in MacLISP, and this causes one incompatibility -- (RETURN (VALUES ...)) on the LISPM might return only one value, but in MacLISP it will return as many values as are provided by the VALUES; also, if FOO is a function returning multiple values, then (RETURN (FOO)) will "pass them all thru" doing essentially what MULTIPLE-VALUE-RETURN does on the LISPM. 1e) VALUES-LIST is a SUBR of one argument, a list, which it "spreads out" into the "return-values vector"; Thus (VALUES-LIST '(1 B 3)) is the same as (VALUES 1 'B 3). RETURN-LIST macroexpands into something like (MULTIPLE-VALUE-RETURN (VALUES-LIST ...)) As mentioned above for MULTIPLE-VALUE-RETURN, there is the implicit LISPM/MacLISP incompatibility about RETURN. 1f) MULTIPLE-VALUE-BIND -- a form is to be evaluated, returning several values, and *then* a lambda-binding contour is created, with the values bound to some variables; following that, the body of and implicit PROGN is executed. Example: (MULTIPLE-VALUE-BIND (A B C) (GET-THREE-VALS ...) (COGITATE-UPON A) (LIST B C)) 1G) SI:CHECK-MULTIPLICITIES **** is called whenever MULTIPLE-VALUE or MULTIPLE-BIND have more variables than there are returned values; the value of SI:CHECK-MULTIPLICITIES, as a variable, then determines what to do (default setting is null): () -- means pad out unsupplied multiple-return-values with nulls; CERROR -- means run an error if not enough values supplied; any thing else should be a function to funcall with an argument which is the number of variables minus one (*:ARn contains the actual number of returned values). Remember also that MULTIPLE-VALUE depends upon a "return-values vector" being set up by the function called, and thus constructs like (MULTIPLE-VALUE (v1 v2) (PROG1 (MANY-VALUED-FUN a1 a3) (SOMETHING-ELSE))) will not work in general; a correct way to do this particular example is (LET (unique-var-1 unique-var-2) (MULTIPLE-VALUE (unique-var-1 unique-var-2) (MANY-VALUED-FUN a1 a3)) (SOMETHING-ELSE) (SETQ v1 unique-var-1 v2 unique-var-2) v1) This "fault" of side-effecting also applies to MULTIPLE-VALUE-LIST. The multiple-value functions operate quite efficiently for 8 or fewer return values -- many of them are "open-coded" by virtue of the code produced by the macroexpansions. Any returned values more than 8 are passed via a cons'ing mechanism. Degenerate forms will generally work OK, provided they make sense; e.g. (VALUES FOOBAZ) is just the same as FOOBAZ, except the internal "number-of-extra-return-values" variable is set up; (MULTIPLE-VALUE (X) ...) again will turn out pretty much like an ordinary SETQ, and (MULTIPLE-VALUE () (FOO)) will turn out pretty much like (FOO), except that the internal count variable is set up. 2) Additional, new "out-of-core" SUBRs and MACROs: Two LSUBRs "<=" and ">=", of 2 or more args are autoloadable from MLSUB file SOURCE-TRANS properties are set up, in the MLMAC file, for LOGAND, LOGIOR, LOGXOR, LOGNOT, FIXNUMP, FLONUMP, EVENP, <=, >=, <, and >. (see item 4 below for "SOURCE-TRANS"), and these are used to generate some other SUBRs in the MLSUB file: LOGAND, LOGIOR, LOGXOR, LOGNOT, LISTP, FIXNUMP, FLONUMP, and EVENP. Non-autoloading macro available in DEFMAC: DEFUNP Non-autoload versions of FMAKUNBOUND, FSYMEVAL, and FSET are in FUNCEL file. Each of <= and >= take two or more arguments; in addition, SOURCE-TRANS properties are set up for <=, >=, < ,and > so that the case of three or more arguments are "wrapped up in a LAMBDA" and the basic open-coding action of the COMPLR on the binary version can be used. NILAID permits usage of any of <, <=, >=, >, <$, <=$, >=$, and >$ with two or more arguments; the "$" versions are for floating-point. In conjunction with the functions which get SOURCE-TRANS properties from the MLMAC file, there are SUBR definitions of them in this file (MLSUB, which is acronymic for "MacLisp SUBrs"): LOGAND, LOGIOR, LOGXOR, LOGNOT, FIXNUMP, FLONUMP, and EVENP. For example, the definition of EVENP can be (DEFUN EVENP (X) (EVENP X)) because the SOURCE-TRANS's cause "(EVENP X)" to expand into "(NOT (ODDP X))"; similar tactics are used for multiple-argumented funtions like LOGXOR etc. Non-autoloading macro available in DEFMAC: DEFUNP As on the LISPM, (DEFUNP FOO (<args>) e1 e2 ... en) macroexpands into (DEFUN FOO (<args>) (PROG () e1 e2 (RETURN en))) Non-autoload versions of FMAKUNBOUND, FSYMEVAL, and FSET are in FUNCEL file. By loading in the EXTEND feature, a pseudo SUBR object can be created and manipulated; thus reasonable versions of the LISPM/NIL functions FMAKUNBOUND, FSYMEVAL, and FSET are implemented. This facility is pre-loaded into NILAID. 3) Default value for DEFUN&-CHECK-ARGS is now (), and whenever &OPTIONAL or &REST args are specified, the "args property" of the symbol will be set. DEFUN&-CHECK-ARGS is the variable which says whether or not there should be code in the function itself to do number-of-args checking. The interpreter, and "UUO" handler, when in *RSET mode, will check the number of arguments passed to a LSUBR/SUBR against the "args property", which is retrieved and set by the ARGS function. 4) SOURCE-TRANS properties for COMPLR act almost like LISPM "optimizers". It is now possible to carry out "code-transformations" in COMPLR by means of the SOURCE-TRANS mechanism. When compiling a form whose CAR is a symbol, the compiler will check for a SOURCE-TRANS property on the symbol. The value of this propery should be a list of transformation routines, each of which must be a function of one argument. Furthermore, each transformation routine must return two values (e.g., via VALUES), the first being the transformed form and the second being a flag which, when non-null, indicates that the transformation routine has "done something". The compiler applies each transformation routine in turn, passing the form to be transformed as the sole argument. If the transformation routine returns a second value of () then it is considered to have "done nothing" and the next transformation routine is tried; otherwise the routine is considered to have "done something" and the entire process begins anew with the first transformation routine. The transformation of the original form is complete only after all transformation routines have been tried and "done nothing". This transformation procedure is carried out fully before any macro expansion is attempted. Note well, that this differs from the LISPM facility in that the translating functions *must* return at least two values. 5) FILE-EXIT-FUNCTIONS is a new global variable which is lambda-bound to the value of FILE-EXIT-FUNCTIONS-DEFAULT by LOAD and FASLOAD. It holds a list of functions of 1 arg to be run at end of loading. The argument supplied to each function is null if loading completed successfully; otherwise it is the file-array of the file being aborted. This provision uses the UNWIND-PROTECT mechanism, so these functions will be called even if the file is aborted by ^G or *THROW. The initial setting of FILE-EXIT-FUNCTIONS-DEFAULT is null, so if you set it to something else, those functions will be run at the end of every file loading; typically, a file itself may push forms onto FILE-EXIT-FUNCTIONS to provide for individual "cleanup".