The syntax of LISP is very simple, in the sense that it can be described concisely, but not in the sense that LISP programs are easy to read or write! This simplicity of syntax is achieved by, and at the expense of, extensive use of explicit structuring, namely grouping through parenthesization. Unlike many languages, there are no reserved words in LISP such as {lisp IF}, {lisp THEN}, {lisp FOR}, {lisp DO}, etc., nor reserved characters like {lisp +}, {lisp -}, {lisp =}, {lisp _}, etc. The only special characters are left and right parentheses and period, which are used for indicating structure, and space and end-of-line, which are used for delimiting identifiers. This eliminates entirely the need for parsers and precedence rules in the LISP interpreter and compiler, and thereby makes program manipulation of LISP programs straightforward. In other words, a program that "looks at" other LISP programs does not need to incorporate a lot of syntactic information. For example, a LISP interpreter can be written in one or two pages of LISP code. It is for this reason that LISP is by far the most suitable, and frequently used, programming language for writing programs that deal with other programs as data, e.g., programs that analyze, modify, or construct other programs. However, it is precisely this same simplicity of syntax that makes LISP programs difficult to read and write (especially for beginners). 'Pushing down' is something programs do very well, and people do poorly. As an example, consider the following two "equivalent" sentences: "The rat that the cat that the dog that I owned chased caught ate the cheese." versus "I own the dog that chased the cat that caught the rat that ate the cheese." Natural language contains many linguistic devices such as that illustrated in the second sentence above for minimizing embedding, because embedded sentences are more difficult to grasp and understand than equivalent non-embedded ones (even if the latter sentences are somewhat longer). Similarly, most high level programming languages offer syntactic devices for reducing apparent depth and complexity of a program: the reserved words and infix operators used in ALGOL-like languages simultaneously delimit operands and operations, and also convey meaning to the programmer. They are far more intuitive than parentheses. In fact, since LISP uses parentheses (i.e., lists) for almost all syntactic forms, there is very little information contained in the parentheses for the person reading a LISP program, and so the parentheses tend mostly to be ignored: the meaning of a particular LISP expression for people is found almost entirely in the {it words}, not in the structure. For example, the expression {lisp (COND (EQ N 0) 1) (T TIMES N FACTORIAL ((SUB1 N)))} is recognizable as factorial even though there are five misplaced or missing parentheses. Grouping words together in parentheses is done more for LISP's benefit, than for the programmer's. CLISP is designed to make Interlisp programs easier to read and write by permitting the user to employ various infix operators, {lisp IF} statements ({PageRef Tag IFstatement}), and iterative statements ({PageRef Tag IterativeStatement}), which are automatically converted to equivalent Interlisp expressions when they are first interpreted. For example, factorial could be written in CLISP: {lisp (IF N=0 THEN 1 ELSE N*(FACTORIAL N-1))} Note that this expression would become an equivalent {fn COND} after it had been interpreted once, so that programs that might have to analyze or otherwise process this expression could take advantage of the simple syntax. There have been similar efforts in other LISP systems. CLISP differs from these in that it does not attempt to {it replace} the LISP syntax so much as to {it augment} it. In fact, one of the principal criteria in the design of CLISP was that users be able to freely intermix LISP and CLISP without having to identify which is which. Users can write programs, or type in expressions for evaluation, in LISP, CLISP, or a mixture of both. In this way, users do not have to learn a whole new language and syntax in order to be able to use selected facilities of CLISP when and where they find them useful. CLISP is implemented via the error correction machinery in Interlisp (see {PageRef Tag DWIM}). Thus, any expression that is well-formed from Interlisp's standpoint will never be seen by CLISP (i.e., if the user defined a function IF, he would effectively turn off that part of CLISP). This means that interpreted programs that do not use CLISP constructs do not pay for its availability by slower execution time. In fact, the Interlisp interpreter does not "know" about CLISP at all. It operates as before, and when an erroneous form is encountered, the interpreter calls an error routine which in turn invokes the Do-What-I-Mean (DWIM) analyzer which contains CLISP. If the expression in question turns out to be a CLISP construct, the equivalent Interlisp form is returned to the interpreter. In addition, the original CLISP expression, is modified so that it {it becomes} the correctly translated Interlisp form. In this way, the analysis and translation are done only once. Integrating CLISP into the Interlisp system (instead of, for example, implementing it as a separate preprocessor) makes possible Do-What-I-Mean features for CLISP constructs as well as for pure LISP expressions. For example, if the user has defined a function named {lisp GET-PARENT}, CLISP would know not to attempt to interpret the form {lisp (GET-PARENT)} as an arithmetic infix operation. (Actually, CLISP would never get to see this form, since it does not contain any errors.) If the user mistakenly writes {lisp (GET-PRAENT)}, CLISP would know he meant {lisp (GET-PARENT)}, and not {lisp (DIFFERENCE GET PRAENT)}, by using the information that {lisp PRAENT} is not the name of a variable, and that {lisp GET-PARENT} is the name of a user function whose spelling is "very close" to that of {lisp GET-PRAENT}. Similarly, by using information about the program's environment not readily available to a preprocessor, CLISP can successfully resolve the following sorts of ambiguities: {Begin Numberedlist resolve ambiguities} {Item {lisp (LIST X*FACT N)}, where {lisp FACT} is the name of a variable, means {lisp (LIST (X*FACT) N)}. } {Item {lisp (LIST X*FACT N)}, where {lisp FACT} is {it not} the name of a variable but instead is the name of a function, means {lisp (LIST X*(FACT N))}, i.e., {lisp N} is {lisp FACT}'s argument. } {Item {lisp (LIST X*FACT(N))}, {lisp FACT} the name of a function (and not the name of a variable), means {lisp (LIST X*(FACT N))}. } {Item cases (1), (2) and (3) with {lisp FACT} misspelled! } {End Numberedlist resolve ambiguities} The first expression is correct both from the standpoint of CLISP syntax and semantics and the change would be made without the user being notified. In the other cases, the user would be informed or consulted about what was taking place. For example, to take an extreme case, suppose the expression {lisp (LIST X*FCCT N)} were encountered, where there was both a function named {lisp FACT} and a variable named {lisp FCT}. The user would first be asked if {lisp FCCT} were a misspelling of {lisp FCT}. If he said YES, the expression would be interpreted as {lisp (LIST (X*FCT) N)}. If he said NO, the user would be asked if {lisp FCCT} were a misspelling of {lisp FACT}, i.e., if he intended {lisp X*FCCT N} to mean {lisp X*(FACT N)}. If he said YES to this question, the indicated transformation would be performed. If he said NO, the system would then ask if {lisp X*FCCT} should be treated as CLISP, since {lisp FCCT} is not the name of a (bound) variable.{foot This question is important because Interlisp users may have programs that employ identifiers containing CLISP operators. Thus, if CLISP encounters the expression {lisp A/B} in a context where either {lisp A} or {lisp B} are not the names of variables, it will ask the user if {lisp A/B} is intended to be CLISP, in case the user really does have a free variable named {lisp A/B}. }{comment endfootnote} If he said YES, the expression would be transformed, if NO, it would be left alone, i.e., as {lisp (LIST X*FCCT N)}. Note that we have not even considered the case where {lisp X*FCCT} is itself a misspelling of a variable name, e.g., a variable named {lisp XFCT} (as with {lisp GET-PRAENT)}. This sort of transformation would be considered after the user said NO to {lisp X*FCCT N -> X*(FACT N)}. Note: Through the discussion above, we speak of CLISP or DWIM asking the user. Actually, if the expression in question was typed in by the user for immediate execution, the user is simply informed of the transformation, on the grounds that the user would prefer an occasional misinterpretation rather than being continuously bothered, especially since he can always retype what he intended if a mistake occurs, and ask the programmer's assistant to {lisp UNDO} the effects of the mistaken operations if necessary. For transformations on expressions in user programs, the user can inform CLISP whether he wishes to operate in {index CAUTIOUS (DWIM mode)}{lisp CAUTIOUS} or {index TRUSTING (DWIM mode)}{lisp TRUSTING} mode. In the former case (most typical) the user will be asked to approve transformations, in the latter, CLISP will operate as it does on type-in, i.e., perform the transformation after informing the user. CLISP can also handle parentheses errors caused by typing {lisp 8} or {lisp 9} for "{lisp (}" or "{lisp )}". (On most terminals, {lisp 8} and {lisp 9} are the lower case characters for "{lisp (}" and "{lisp )}", i.e., "{lisp (}" and {lisp 8} appear on the same key, as do "{lisp )}" and {lisp 9}.) For example, if the user writes {lisp N*8FACTORIAL N-1}, the parentheses error can be detected and fixed before the infix operator {lisp *} is converted to the Interlisp function {fn TIMES}. CLISP is able to distinguish this situation from cases like {lisp N*8*X} meaning {lisp (TIMES N 8 X)}, or {lisp N*8X}, where {lisp 8X} is the name of a variable, again by using information about the programming environment. In fact, by integrating CLISP with DWIM, CLISP has been made sufficiently tolerant of errors that almost everything can be misspelled! For example, CLISP can successfully translate the definition of {lisp FACTORIAL}: {lispcode (IFF N=0 THENN1 ESLE N*8FACTTORIALNN-1)} to the corresponding {lisp COND}, while making 5 spelling corrections and fixing the parenthesis error.{foot CLISP also contains a facility for converting from Interlisp back to CLISP, so that after running the above incorrect definition of {lisp FACTORIAL}, the user could "clispify" the now correct version to obtain {lisp (IF N=0 THEN 1 ELSE N*(FACTORIAL N-1))}. }{comment endfootnote} This sort of robustness prevails throughout CLISP. For example, the iterative statement permits the user to say things like: {lispcode (FOR OLD X FROM M TO N DO (PRINT X) WHILE (PRIMEP X))} However, the user can also write {lisp OLD (X_M)}, {lisp (OLD X_M)}, {lisp (OLD (X_M))}, permute the order of the operators, e.g., {lisp (DO PRINT X TO N FOR OLD X_M WHILE PRIMEP X)}, omit either or both sets of parentheses, misspell any or all of the operators {lisp FOR}, {lisp OLD}, {lisp FROM}, {lisp TO}, {lisp DO}, or {lisp WHILE}, or leave out the word {lisp DO} entirely! And, of course, he can also misspell {lisp PRINT}, {lisp PRIMEP}, {lisp M} or {lisp N}! In this example, the only thing the user could not misspell is the first {lisp X}, since it specifies the {it name} of the variable of iteration. The other two instances of {lisp X} could be misspelled. CLISP is well integrated into the Interlisp system. For example, the above iterative statement translates into an following equivalent Interlisp form using {fn PROG}, {fn COND}, {fn GO}, etc. When the interpreter subsequently encounters this CLISP expression, it automatically obtains and evaluates the translation. Similarly, the compiler "knows" to compile the translated form. However, if the user {fn PRETTYPRINT}s his program, {fn PRETTYPRINT} "knows" to print the original CLISP at the corresponding point in his function. Similarly, when the user edits his program, the editor keeps the translation invisible to the user. If the user modifies the CLISP, the translation is automatically discarded and recomputed the next time the expression is evaluated. In short, CLISP is not a language at all, but rather a system. It plays a role analagous to that of the programmer's assistant ({PageRef Tag ProgAsst}). Whereas the programmer's assistant is an invisible intermediary agent between the user's console requests and the Interlisp executive, CLISP sits between the user's programs and the Interlisp interpreter. Only a small effort has been devoted to defining the core syntax of CLISP. Instead, most of the effort has been concentrated on providing a facility which "makes sense" out of the input expressions using context information as well as built-in and acquired information about user and system programs. It has been said that communication is based on the intention of the speaker to produce an effect in the recipient. CLISP operates under the assumption that what the user said was {it intended} to represent a meaningful operation, and therefore tries very hard to make sense out of it. The motivation behind CLISP is not to provide the user with many different ways of saying the same thing, but to enable him to worry less about the {it syntactic} aspects of his communication with the system. In other words, it gives the user a new degree of freedom by permitting him to concentrate more on the problem at hand, rather than on translation into a formal and unambiguous language. DWIM and CLISP are invoked on iterative statements because {fn CAR} of the iterative statement is not the name of a function, and hence generates an error. If the user defines a function by the same name as an i.s. operator, e.g., {lisp WHILE}, {lisp TO}, etc., the operator will no longer have the CLISP interpretation when it appears as {fn CAR} of a form, although it will continue to be treated as an i.s. operator if it appears in the interior of an i.s. To alert the user, a warning message is printed, e.g., {lisp (WHILE DEFINED, THEREFORE DISABLED IN CLISP)}.{index DEFINED, THEREFORE DISABLED IN CLISP Error} {Begin SubSec CLISP Interaction with User} {Title CLISP Interaction with User} {Text {index CLISP interaction with user} Syntactically and semantically well formed CLISP transformations are always performed without informing the user. Other CLISP transformations described in the previous section, e.g., misspellings of operands, infix operators, parentheses errors, unary minus - binary minus errors, all follow the same protocol as other DWIM transformations ({PageRef Tag DWIM}). That is, if DWIM has been enabled in {index TRUSTING (DWIM mode)}{lisp TRUSTING} mode, or the transformation is in an expression typed in by the user for immediate execution, user approval is not requested, but the user is informed.{foot However, in certain situations, DWIM will ask for approval even if DWIM is enabled in {index TRUSTING (DWIM mode)}{lisp TRUSTING} mode. For example, the user will always be asked to approve a spelling correction that might also be interpreted as a CLISP transformation, as in {lisp LAST-ELL -> LAST-EL}. }{comment endfootnote} However, if the transformation involves a user program, and DWIM was enabled in {index CAUTIOUS (DWIM mode)}{lisp CAUTIOUS} mode, the user will be asked to approve. If he says NO, the transformation is not performed. Thus, in the previous section, phrases such as "one of these (transformations) succeeds" and "the transformation {lisp LAST-ELL -> LAST-EL} would be found" etc., all mean if the user is in {lisp CAUTIOUS} mode and the error is in a program, the corresponding transformation will be performed only if the user approves (or defaults by not responding). If the user says NO, the procedure followed is the same as though the transformation had not been found. For example, if {lisp A*B} appears in the function {lisp FOO}, and {lisp B} is not bound (and no other transformations are found) the user would be asked {lisp A*B [IN FOO] TREAT AS CLISP ?}{foot The waiting time on such interactions is three times as long as for simple corrections, i.e., 3*{var DWIMWAIT}. }{comment endfootnote} If the user approved, {lisp A*B} would be transformed to {lisp (ITIMES A B)}, which would then cause a {lisp U.B.A. B} error in the event that the program was being run (remember the entire discussion also applies to {lisp DWIMIFY}ing). If the user said {lisp NO}, {lisp A*B} would be left alone.{foot If the value of {index CLISPHELPFLG Var}{var CLISPHELPFLG}={lisp NIL} (initally {lisp T}), the user will not be asked to approve any clisp transformation. Instead, in those situations where approval would be required, the effect is the same as though the user had been asked and said {lisp NO}. }{comment endfootnote} }{End SubSec CLISP Interaction with User}