5/22/74    JONL  

Brief Synopsis:    for LISP 838 and greater

1) SUSPEND - new function, LSUBR of 0 or 1 arguments, like MACDMP,
   but can continue where the computation left off, rather than 
   restarting at top level.
2) MUNKAM  is the inverse of MAKNUM.  On the PDP10 system, is pretty
   much the same as CDR, except that the argument is required to be
   a fixnum, and the COMPLRs will open-code MUNKAM.
3) RANDOM will accept two arguments, as a means of "seeding" it.
   Also, a slight deficiency has been noted.
4) A programmable features list for (STATUS FEATURE foo), and an aid,
   (SSTATUS LINMODE T), for systems with line rather than character 
   oriented TTY input.
5) ARRAYCALL, SUBRCALL, AND LSUBRCALL are now all FSUBRs, and
   take an extra argument to aid NCOMPLR in open-coding these 
   applications.  Disregard  any previous notes on these functions,
   and note well below.
6) Examples of some particularly useful lisp macros, especially for 
   users of ARRAYCALL, SUBRCALL, and LSUBRCALL.
7) The compiler declaration ARRAY* has been extended to allow 
   information about the ranges of indices.  Also, NCOMPLR now uses 
   its own private obarray when compiling a file, in addition to its 
   own private readtable.

--------------------------------------------------------------------

1) (SUSPEND) may be executed at any point in a computation, and 
   control will be returned to the LISP's  superior [DDT or monitor].
   Accumulators, push-down stacks, and other variables will be saved,
   and its starting address will be set so that if the job be dumped
   on dsk, and reloaded at some future time, starting it again will
   cause it to resume where the computation and continue just after 
   the call to SUSPEND.  One limitation:  if any input-output devices
   are in use other than the TTY, SUSPEND will error with a fail-act.
   (SUSPEND s), like (MACDMP s), passes the characters of the symbol
   s to the superior job as a valret string.

2) By "inverse of MAKNUM", the following is meant:
   (EQ X (MUNKAM (MAKNUM X))) evaluates to T for all X.  Shortly, 
   the MULTICS implementation will have a reasonable version of 
   MAKNUM and MUNKAM implemented, so that one may write a 
   hash-coder-on-EQ for s-expressions.  Previous notes in LISP ARCHIV
   have given examples on how to hash an s-expression on EQUAL.  By 
   replacing "(\ (SXHASH X) 777))" with "(\ (MAKNUM X) 777)" one 
   will have a hasher on EQ.

3) By "seeding" RANDOM, one may obtain a variety of starting points,
   corresponding to the various internal states of the two-word state 
   register.  Any two successive outputs of RANDOM will do as the 
   two words for a seed; for example, (SETQ X (RANDOM) Y (RANDOM))
   will preserve the current state of the random number generator 
   in the variables X and Y, and the state may be restored to that
   state [after, possibly, further usage of RANDOM] by (RANDOM X Y).
   Users of RANDOM should take note of a fact which Bill Gosper 
   ferreted out of Knuth - this random number genertor flunks the 
   3-way serial test.  That is, if triplets of "random" numbers 
   <x[n], y[n], z[n]> are generated by clumping together the 
   3n, 3n+1, and 3n+2 outputs of RANDOM, then there will be an   
   interdependency among the triples such that half of all triples
    will be missed - not particularly good for picking "random" 
   points in 3-space.  One way out of this bind is simply
   to use only every other output of RANDOM in generting the triples.

4) As described in previous notes, there is an internal list of 
   "features" describing which of the various MACLISP options are 
   actually available in the LISP being used, and which time-sharing
   system it is running under.  Now the user can create his own
   feature names and add, or delete, from this list at will.  
		(STATUS FEATURE FOO)
   is non-NIL if and only if FOO is on the features list; 
		(SSTATUS FEATURE FOO)
   will add FOO to the features list, and 
		(SSTATUS NOFEATURE FOO)
   will delete it.
			(SSTATUS LINMODE T)
   tells the time-sharing system not to activate your job while
   waiting for TTY input until a carriage-return is typed.  For the 
   TOPS-10 system, it means the basic input instruction is INCHRW 
   instead of INCHR, and that the time-sharing system will handle
   rubouts until the carriage-return is typed.  Since the ITS system
   does not handle rubouts under any circumstances, many  users want
   a mode under which the rubout handler of the MACLISP reader will 
   be effective on a line-by-line basis, and under which no read
   reading is done until a carriage-return is typed.  This can be
   achieved as follows:
	(SSTATUS SYNTAX 13. 501540)
		;makes <cr> an invisible force-feed char
	(SSTATUS LINMODE T)
		;tells ITS to sleep until <cr> or <rubout>
	(SSTATUS TTYREAD T)
		;tells LISP's reader to forget about looking for 
		;"balanced" s-expressions before actually gobbling 
		;up characters from the TTY
   It is worthwile to note here that the "force-feed" option on <cr>,
   and the TTYREAD option are properties of LISP's readtable, while 
   the LINMODE option is a property of the LISP's relation with the 
   time-sharing system.


5) There has long been a certain ambiguity in LISP with respect to
   the meaning of an atomic function.  For (FOO X Y), most LISP
   systems will scan the property list of FOO to see if there are 
   any functional properties [such as SUBR, EXPR, etc], and if so,
   use the first one found as the functional-interpretation of FOO;
   if none are found, then the value of FOO as a variable is picked up,
   and the function-hunting process continues recursively.  Some other 
   systems always pick up the variable value, and never resort to 
   storing subroutine addresses, or LAMBDA forms, as "properties" on 
   a property list.  The function FUNCALL was implemented as a means 
   of directing the MACLISP evaluator first to the variable 
   value as function rather than starting out on the functional
   properties.  Thus, (FUNCALL FOO X Y) is equivalent to 
   (APPLY FOO (LIST X Y)).  However, FUNCALL is essentially an 
   interpretation, and the COMPLR can not open-code the dispatch to 
   the function of interest unless more is known about its calling
   conventions.  For this reason, ARRAYCALL, LSUBRCALL, and SUBRCALL
   have been implemented as FSUBRs.  The general forms are
	(ARRAYCALL type ap i1 . . . in)
	(LSUBRCALL type lfun arg1 . . . argn)
	(SUBRCALL type fun arg1 . . . argn)
   type should be either "FIXNUM", "FLONUM", "T", or "NIL", depending
   on the resulting type of value returned by the function [or on the
   array type, in the case of ARRAYCALL.  Both T-type and NIL-type 
   arrays may be specified by NIL here, which simply means
   "s-expression" array rather than "numeric" array.].  ap should 
   evaluate to an array pointer such as created by *ARRAY 
   [(1) returned by *ARRAY if its first argument is NIL, or (2) put
   on the property list of the given non-NIL symbol].  lfun should 
   evaluate to an LSUBR pointer, which on the PDP10 systems is obtained
   only by doing (GET 'FOO 'LSUBR) for some LSUBR FOO;  similarly, fun 
   should evaluate to a SUBR pointer.  The reason the type argument is 
   required is that NCOMPLR can generate optimal code for these 
   applications.  Versions of NCOMPLR greater than 454 will code these three 
   functions open [COMPLR will not be nearly so optimal in its codings of these 
   three.  Neither will COMPLR actually open-code array references.].
   in the case  of SUBRCALL and LSUBRCALL, the type info is mainly
   an aid to NCOMPLR, and type NIL could always be used as default; 
   however, using type FIXNUM or FLONUM where NIL is required 
   will result in wrong code.  For ARRAYCALL, it will be necessary
   always to have the correct type info since wrong code would result
   from any kind of type mismatch.



    EXAMPLE:  suppose you have done
      (SETQ BARODD (ARRAY NIL FIXNUM N)  BAREVEN (ARRAY NIL FIXNUM N))
    Now at this point, both BARODD and BAREVEN hold as value an array
    pointer.   They would have ARRAY properties on their property list
    if, for example, (ARRAY BARODD FIXNUM N) had been done instead.
    Then the following will fill BARODD with the first N odd integers,
    and BAREVEN with the first N even integers:
      (DO I 1 (1+ I) (> I (* 2 N))
	 (STORE (ARRAYCALL FIXNUM 
			   (COND ((ODDP I) BARODD) (BAREVEN))
			   (/ (1- I) 2))
		I))


6)	EXAMPLE USING MACROS FOR SIMPLIFIED SYNTAX:
      Assuming BARODD and BAREVEN as above [that is, variables that 
    have been set to some array pointer], let us define two macros
    (DEFUN MACRO BO (X) 
	(SUBST (CADR X) 'INDEX '(ARRAYCALL FIXNUM BARODD INDEX)))
    (DEFUN MACRO BE (X)
	(SUBST (CADR X) 'INDEX '(ARRAYCALL FIXNUM BAREVEN INDEX)))
    Then we could fill BARODD and BAREVEN as follows:
      (DO J 1 (1+ J) (> J N) (STORE (BE (1- J)) (* 2 J)))
      (DO J 0 (1+ J) (NOT (< J N)) (STORE (BO J) (1+ (* 2 J))))
    Admittedly, this saves a lot of typing.  But suppose you have a 
    host of such array variables that you would like to abbreviate 
    with such a MACRO.  Typing in all the macro definitions could be 
    tediously repetitive.  Consider the following macro-defining macro,
    and some of its uses:
      (DEFUN MACRO ABBA (Y) 
	(SUBLIS (LIST (CONS 'SHORT (CADR Y)) 
		      (CONS 'LONG (CADDR Y))
		      (CONS 'TYPE (CADDR Y)))
		'(DEFUN MACRO SHORT (X) 
		    (SUBST (CDR X) 
			   'INDEXLIST 
			   '(ARRAYCALL TYPE LONG . INDEXLIST)))))
    Now we might use ABBA to produce the macro for BE, but note that 
    the form of the macro is slightly different - the main body of the
    macro output appears to be a dotted-list rather than a standard 
    list.  This is so that arrays of varying numbers of dimensions may
    have their abbreviations defined by the same super-macro.
      (ABBA BO BARODD FIXNUM)
    expands into
      (DEFUN MACRO BO (X) 
	  (SUBST (CDR X) 
		  'INDEXLIST 
		  '(ARRAYCALL FIXNUM BARODD . INDEXLIST)))
    which then causes the appropriate macro definition for BO.  As 
    you would expect, then, (BO J) expands into 
	(ARRYACALL FIXNUM BARODD J)
    But consider the two-dimensional hash array HASH defined as 
	(SETQ HASH (ARRAY NIL T 37 37))
    Then (ABBA HA HASH T) defines HA so that (HA 3 (+ N 2)) expands 
    into (ARRAYCALL T HASH 3 (+ N 2))

 
    Guy Steele has accumulated a file of sophisticated macros and 
    macro-defining macros, and the interested may consult with him
    about them.


7) In order to get maximal speed from open-compiled array references,
   you may inform NCOMPLR of the actual ranges of the array 
   indices.  Thus a two-dimensional array of FIXNUMS, size 3 by 4, 
   could be declared by:
	(ARRAY* (FIXNUM (CIR 3 4)))
   Even partial information will be useful;  a NIL or ? in index 
   positions will indicate that no information is available about that 
   particular dimension.  For example, to add to the above declaration
   that for a two-dimensional array in which only the column dimension
   is known in advance, one could say:
	(ARRAY* (FIXNUM (CORL ? 4) (CIR 3 4)))
   The previous syntax for ARRAY* is still available, and one 
   should note that the following two forms both convey the same 
   information:
	(ARRAY* (NOTYPE DXA 1 CIR 2))
	(ARRAY* (NOTYPE (DXA NIL) (CIR ? ?)))

   Also, NCOMPLR now uses its own private obarray when compiling a 
   file, in addition to its own private readtable; they are contained,
   respectively, in the two global variables COBARRAY and CREADTABLE.
   If you have the practice of escaping to top-level LISP, and 
   loading in some of your own functions, be sure to do this stuff 
   under the correct obarray and readtable.  E.G., you might do
	((LAMBDA (OBARRAY READTABLE)
		 (FASLOAD MY FUNS DSK LOSER))
	    COBARRAY CREADTABLE)