{index *PRIMARY* Executive} {Index *PRIMARY* Interlisp-D executive} 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. {index *PRIMARY* Programmer's assistant} {index P.A.} 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. {index *PRIMARY* History lists} The programmer's assistant facility features the use of memory structures called "history lists." 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 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.} 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, BREAK1 accept user inputs, recognizes and executes certain break commands and macros, and interprets anything else as Interlisp expressions for evaluation. To interface BREAK1 with the programmer's assistant required three small modifications to BREAK1: (1) input was to be obtained via LISPXREAD instead of READ; (2) instead of calling EVAL or APPLY directly, BREAK1 was to give those inputs it could not interpret to LISPX, and (3) any commands or macros handled by BREAK1 rather than LISPX were to be explicitly stored on the history list by calling the function 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: EVAL, (CAR !VALUE), and OK, at the next break, he could achieve the same effect by typing REDO FROM EVAL. This would cause the assistant to unread the three expressions EVAL, (CAR !VALUE), and OK. Because of (1), the next "input" seen by BREAK1 would then be EVAL, which BREAK1 would interpret. Next would come (CAR !VALUE), which would be given to LISPX to evaluate, and then would come OK, which BREAK1 would again process. Thus, by virtue of unreading, history operations will work even for those inputs not interpretable by LISPX, in this case, EVAL and OK. 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 Note} {Begin SubSec Input Formats} {Title Input Formats} {Text The Interlisp-D executive accepts inputs in the following formats: {Begin Labeledlist Input Formats} {Label {index *PRIMARY* EVALV-format input}EVALV-format input} {Item If the user types a single litatom, followed by a carriage-return, the value of the litatom is returned. For example, if the value of the variable {lisp FOO} is the list {lisp (A B C)}: {lispcode ←FOO{cr} (A B C)} } {Label {index *PRIMARY* EVAL-format input}EVAL-format input} {Item If the user types a regular Interlisp expression, beginning with a left parenthesis or square bracket and terminated by a matching right parenthesis or square bracket, the form is simply passed to {fn EVAL} for evaluation. A right bracket matches any number of left parentheses, back to the last left bracket or the entire expression. 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)) 7 ←(PLUS 1 (TIMES 2 3] 7 ←(PLUS 1 (TIMES{cr} 2 3] 7} } {Label {index *PRIMARY* APPLY-format input}APPLY-format input} {Item 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. The input is terminated by the matching right parenthesis or bracket. 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)}. 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 (see {PageRef Term NLAMBDA functions}). For example, typing {lisp SETQ(FOO BAR)} will set {lisp FOO} to the {it value} of {lisp BAR}, not to the litatom {lisp BAR} itself. } {Label Other input} {Item Sometimes, a user does not want to terminate the input when a closing parenthesis is typed. For example, some programmer's assistant commands take several arguments, some of which can be lists. If the user types a sequence of litatoms and lists 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, the Interlisp-D executive interprets it differently depending on the number of expressions typed. If only one expression is typed (a litatom), it is interpreted as an EVALV-format input, and the value of the litatom is returned: {lispcode ←FOO<space>{cr} (A B C)} If exactly two expressions are typed, it is interpreted as APPLY-format input: {lispcode ←LIST (A B){cr} (A B)} If three or more expressions are typed, it is interpreted as EVAL-format input. To warn the user, the full expression is printed out before it is executed. For example: {lispcode ←PLUS (TIMES 2 3) 1{cr} = (PLUS (TIMES 2 3) 1) 7} Note: If {index LISPXREADFN Var}{var LISPXREADFN} ({PageRef Var LISPXREADFN}) is set to {fn READ} (rather than the default, {fn TTYINREAD}), then whenever one of the elements typed is a list and the list is terminated by a right parenthesis or bracket, Interlisp will type a carriage-return and {index ... (printed during input)}"{lisp ...}" to indicate that further input will be accepted. The user can type further expressions or terminate the whole expression by a carriage-return. } {End Labeledlist Input Formats} }{End SubSec Input Formats}