{Begin SubSec Introduction} {Title Introduction} {Text With any interactive computer language, the user interacts with the system through an "executive", which interprets and executes typed-in commands. In most implementations of Lisp, the executive is a simple "read-eval-print" loop, which repeatedly reads a Lisp expression, evaluates it, and prints out the value of the expression. Interlisp has an executive which allows a much greater range of inputs, other than just regular Interlisp expressions. In particular, the Interlisp executive implements a facility known as the "programmer's assistant" (or "p.a."). The central idea of the programmer's assistant is that the user is addressing an active intermediary, namely his assistant. Normally, the assistant is invisible to the user, and simply carries out the user's requests. However, the assistant remembers what the user has done, so the user can give commands to repeat a particular operation or sequence of operations, with possible modifications, or to undo the effect of specified operations. Like DWIM, the programmer's assistant embodies an approach to system design whose ultimate goal is to construct an environment that "cooperates" with the user in the development of his programs, and frees him to concentrate more fully on the conceptual difficulties and creative aspects of the problem at hand. We will first discuss the various input formats, then the use of commands to the programmer's assistant, and finally how to modify the programmer's assistant for specialized uses. {Begin SubSec Input Formats} {Title Input Formats} {Text The Interlisp executive accepts inputs in the following formats: (1) A single litatom, followed by a carriage-return. The value of the litatom is returned. For the purposes of this discussion, we will call this EVALV-format. (2) A regular Interlisp expression, beginning with a left parenthesis or square bracket and terminated by a matching right parenthesis or square bracket. A right bracket matches any number of left parentheses, back to the last left bracket or the entire expression. Such an input is known as an "EVAL-format" input, since the form is simply passed to {fn EVAL} for evaluation. Notice that it is not necessary to type a carriage return at the end of such a form; Interlisp will supply one automatically. If a carriage-return is typed before the final matching right parenthesis or bracket, it is treated as a space, and input continues. The following examples are all interpreted the same: {lispcode ←(PLUS 1 (TIMES 2 3)) ←(PLUS 1 (TIMES 2 3] ←(PLUS 1 (TIMES{cr} 2 3]} (3) Often, the user, typing at the keyboard, calls functions with constant argument values, which would have to be quoted if the user typed it in "EVAL-format". For convience, if the user types a litatom immediately followed by a list form, the litatom is {fn APPLY}ed to the elements within the list, unevaluated. For example, typing {lisp LOAD(FOO)} is equivalent to typing {lisp (LOAD 'FOO)}, and {lisp GETPROP(X COLOR)} is equivalent to {lisp (GETPROP 'X 'COLOR)}. The input is terminated by the matching right parenthesis or bracket. We will call such input "APPLY-format." APPLY-format input is useful in some situations, but note that it may produce unexpected results when an {it nlambda} function is called that explicitly evaluates its arguments. For example, typing {lisp SETQ(FOO BAR)} will set {lisp FOO} to the {it value} of {lisp BAR}, not to {lisp BAR} itself. However, there are times when a user does not want to terminate the input when a closing parenthesis is typed {emdash} especially when giving a command to the programmer's assistant. This leads us to our fourth format. (4) A sequence of litatoms and lists {it beginning with} a litatom and a space (to distinguish it from APPLY-format), terminated by a carriage return or an extra right parenthesis or bracket. If a list is terminated then Interlisp will type a carriage-return and {lisp "..."} to indicate that further input will be accepted. The user can type further expressions or terminate the whole expression by a carriage-return. Once the input is terminated, the programmer's assistant decides how to evaluate the expression. This determination relies on a heuristic that says "If there is only expression, then assume EVALV-format. If there are two expressions, then assume APPLY-format. If there are three or more expressions, then assume EVAL-format." The following inputs are examples of this rule: {lispcode ←FOO<space>{cr} {it same as FOO{cr} {emdash} EVALV-format} ←LIST (A B) ...{cr} {it same as LIST(A B) {emdash} APPLY-format} ←PLUS (TIMES 2 3) ...1{cr} {it same as (PLUS (TIMES 2 3) 1) {emdash} EVAL-format} } } {End SubSec input formats} {Begin SubSec Examples} {Title Examples} {Text So far, we have dealt only with how the executive instructs Interlisp to evaluate input. However, the same scheme also allows the user to give commands directly to the programmer's assistant. In fact, in each of the above cases, it is first determined whether the initial litatom is a command to the programmer's assistant. If so, the normal lisp evaluation process is bypassed. Note that this means that a function or variable with the same name as a programmer's assistant command will not be evaluated (in the normal lisp sense) if it is the first litatom of an expression input to the executive. The programmer's assistant facility features the use of memory structures called "history lists."{index *PRIMARY* history list} A history list is a list of the information associated with each of the individual "events" that have occurred in the system, where each event corresponds to one user input. Associated with each event on the history list is the input and its value, plus other optional information such as side-effects, formatting information, etc. The following dialogue, taken from an actual session at the terminal, contains illustrative (but not necessarily useful) examples and gives the flavor of the programmer's assistant facility in Interlisp. The number before each prompt is the "event number" (see {PageRef Tag EventNumbers}). {lispcode 12←(SETQ FOO 5) 5 13←(SETQ FOO 10) (FOO reset) 10} {it The p.a. notices that the user has reset the value of FOO and informs the user.} {lispcode 14←UNDO SETQ undone. 15←FOO{CR} 5} {it This is the first example of direct communication with the p.a. The user has said to UNDO the previous input to the executive.} {lispcode . . .} {lispcode 25←SET(LST1 (A B C)) (A B C) 26←(SETQ LST2 '(D E F)) (D E F) 27←(FOR X IN LST1 DO (REMPROP X 'MYPROP] NIL} {it The user asked to remove the property MYPROP from the atoms A, B, and C. Now lets assume that is not what he wanted to do, but rather use the elements of LST2.} {lispcode 28←UNDO FOR FOR undone.} {it First he undoes the REMPROP, by undoing the iterative statement. Notice the UNDO accepted an "argument," although in this case UNDO by itself would be sufficient.} {lispcode 29←USE LST2 FOR LST1 IN 27 NIL} {it The user just instructed to go back to event number 27 and substitute LST2 for LST1 and then reexecute the expression. The user could have also specified -2 instead of 27 to specify a relative address.} {lispcode . . .} {lispcode 47←(PUTHASH 'FOO (MKSTRING 'FOO) MYHASHARRAY) "FOO"} {it If MKSTRING was a computationally expensive function (which it is not), then the user might be cacheing its value for later use.} {lispcode 48←USE FIE FUM FOE FOR FOO IN MKSTRING "FIE" "FUM" "FOE"} {it The user now decides he would like to redo the PUTHASH several times with different values. He specifies the event by "IN MKSTRING" rather than PUTHASH.} {lispcode 49←?? USE 48. USE FIE FUM FOE FOR FOO IN MKSTRING ←(PUTHASH (QUOTE FIE) (MKSTRING (QUOTE FIE)) MYHASHARRAY) "FIE" ←(PUTHASH (QUOTE FUM) (MKSTRING (QUOTE FUM)) MYHASHARRAY) "FUM" ←(PUTHASH (QUOTE FOE) (MKSTRING (QUOTE FOE)) MYHASHARRAY) "FOE"} {it Here we see the user ask the p.a. (using the {pacom ??} command) what it has on its history list for the last input to the executive. Since the event corresponds to a programmer's assistant command that evaluates several forms, these forms are saved as the input, although the user's actual input, the p.a. command, is also saved in order to clarify the printout of that event.} }{end subsec Examples} {Begin Note} move to discussion of the function LISPX ??? The function that accepts a user input, saves the input on the history list, performs the indicated computation or p.a. command, and prints the result, is {fn LISPX}. {fn LISPX} is called by {fn EVALQT} and {fn BREAK1}, and in most cases, is synonymous with "programmer's assistant." However, for various reasons, the editor saves its own inputs on a seperate history list, carries out edit commands, and even handles undoing independently of {fn LISPX}. The editor only calls {fn LISPX} to execute a p.a. command, such as {pacom REDO}, {pacom USE}, etc. Therefore we use the term programmer's assistant (loosely) when the discussion applies to features shared by {fn EVALQT}, {fn BREAK} and the editor, and the term {fn LISPX} when we are discussing the specific function. {End Note} As stated earlier, the most common interaction with the programmer's assistant occurs at the top level read-eval-print loop, or in a break, where the user types in expressions for evaluation, and sees the values printed out. In this mode, the assistant acts much like a standard Lisp executive, except that before attempting to evaluate an input, the assistant first stores it in a new entry on the history list. Thus if the operation is aborted or causes an error, the input is still saved and available for modification and/or reexecution. The assistant also notes new functions and variables to be added to its spelling lists to enable future corrections. Then the assistant executes the computation (i.e., evaluates the form or applies the function to its arguments), saves the value in the entry on the history list corresponding to the input, and prints the result, followed by a prompt character{index prompt character} to indicate it is again ready for input. If the input typed by the user is recognized as a p.a. command, the assistant takes special action. Commands such as {pacom UNDO} and {pacom ??} are immediately performed. Commands that involved reexecution of previous inputs, such as {pacom REDO} and {pacom USE}, are achieved by computing the corresponding input expression(s) and then {it unreading} them. The effect of this {index unreading}unreading operation is to cause the assistant's input routine, {index LISPXREAD FN}{fn LISPXREAD}, to act exactly as though these expressions were typed in by the user. These expressions are processed exactly as though they had been typed, except that they are not saved on new and separate entries on the history list, but associated with the history command that generated them. {Begin Note} move to discussion of lispxuserfn or something like that The advantage of this implementation is that it makes the programmer's assistant a callable facility for other system packages as well as for users with their own private executives. For example, {fn BREAK1} accept user inputs, recognizes and executes certain break commands and macros, and interprets anything else as Interlisp expressions for evaluation. To interface {fn BREAK1} with the programmer's assistant required three small modifications to {fn BREAK1}: (1) input was to be obtained via {index LISPXREAD FN}{fn LISPXREAD} instead of {fn READ}; (2) instead of calling {fn EVAL} or {fn APPLY} directly, {fn BREAK1} was to give those inputs it could not interpret to {fn LISPX}, and (3) any commands or macros handled by {fn BREAK1} rather than {index LISPX FN}{fn LISPX} were to be explicitly stored on the history list by calling the function {index HISTORYSAVE FN}{fn HISTORYSAVE}. As a result of these modifications, when the user typed a break command, the command would be stored on the history list as a result of (3). If the user typed in an expression for evaluation, it would be evaluated as before, with the expression and its value both saved on the history list as a result of (2). Now if the user entered a break and typed three inputs: {lisp EVAL}, {lisp (CAR !VALUE)}, and {lisp OK}, at the next break, he could achieve the same effect by typing {lisp REDO FROM EVAL}. This would cause the assistant to unread{index unreading} the three expressions {lisp EVAL}, {lisp (CAR !VALUE)}, and {lisp OK}. Because of (1), the next "input" seen by {fn BREAK1} would then be {lisp EVAL}, which {fn BREAK1} would interpret. Next would come {lisp (CAR !VALUE)}, which would be given to {fn LISPX} to evaluate, and then would come {lisp OK}, which {fn BREAK1} would again process. Thus, by virtue of {it unreading},{index unreading} history operations will work even for those inputs not interpretable by {index LISPX FN}{fn LISPX}, in this case, {lisp EVAL} and {lisp OK}. {End Note} The net effect of this implementation of the programmer's assistant is to provide a facility which is easily inserted at many levels, and embodies a consistent set of commands and conventions for talking about past events. This gives the user the subjective feeling that a single agent is watching everything he does and says, and is always available to help. }{End SubSec Introduction}