{Begin SubSec DWIM Operation}
{Title DWIM Operation}
{Text

{note DWIM was designed and implemented by W. Teitelman. It is discussed in [Tei2].}


{index *BEGIN* unbound atom}
{index *BEGIN* undefined function}

{index *PRIMARY* FAULTEVAL FN}
{index *PRIMARY* FAULTAPPLY FN}

Whenever the interpreter encounters an atomic form with no binding, or a non-atomic form {fn CAR} of which is not a function or function object, it calls the function {fn FAULTEVAL}.  Similarly, when {fn APPLY} is given an undefined function, {fn FAULTAPPLY} is called.  When DWIM is enabled, {fn FAULTEVAL} and {fn FAULTAPPLY} are redefined to first call the DWIM package, which tries to correct the error.  If DWIM cannot decide how to fix the error, or the user disapproves of DWIM's correction (by typing {lisp N}), or the user types {index control-E}control-E, then {fn FAULTEVAL} and {fn FAULTAPPLY} cause an error or break.{foot
If the user types {lisp ↑} to DWIM, DWIM exits by performing {lisp (RETEVAL 'FAULTEVAL '(ERROR!))}, so that an error will be generated at the position of the call to {fn FAULTEVAL}.
}{comment endfootnote}


If DWIM can (and is allowed to) correct the error, it exits by performing {fn RETEVAL} of the corrected form, as of the position of the call to {fn FAULTEVAL} or {fn FAULTAPPLY}.  Thus in the example at the beginning of the chapter, when DWIM determined that {lisp ITIMS} was {lisp ITIMES} misspelled, DWIM called {index RETEVAL FN}{fn RETEVAL} with {lisp (ITIMES N (FACCT 8SUB1 N))}.  Since the interpreter uses the value returned by {fn FAULTEVAL} exactly as though it were the value of the erroneous form, the computation will thus proceed exactly as though no error had occurred.


In addition to continuing the computation, DWIM also repairs the cause of the error whenever possible; in the above example, DWIM also changed (with {fn RPLACA}) the expression {lisp (ITIMS N (FACCT 8SUB1 N))} that caused the error.  Note that if the user's program had {it computed} the form and called {fn EVAL}, it would not be possible to repair the cause of the error, although DWIM could correct the misspelling each time it occurred.


Error correction in DWIM is divided into three categories: unbound atoms, undefined {fn CAR} of form, and undefined function in {fn APPLY}.
Assuming that the user approves DWIM's corrections, the action taken by DWIM for the various types of errors in each of these categories is summarized below.


{Begin SubSec DWIM Correction: Unbound Atoms}
{Title DWIM Correction: Unbound Atoms}
{Text


If DWIM is called as the result of an unbound atom error, it proceeds as follows:

{Begin NumberedList Unbound Atoms}

{Item
If the first character of the unbound atom is {lisp '},{index '} DWIM assumes that the user (intentionally) typed {lisp '{arg ATOM}} for {lisp (QUOTE {arg ATOM})} and makes the appropriate change.  No message is typed, and no approval is requested.

If the unbound atom is just {lisp '} itself, DWIM assumes the user wants the {it next} expression quoted, e.g., {lisp (CONS X '(A B C))} will be changed to
{lisp (CONS X (QUOTE (A B C)))}.  Again no message will be printed or approval asked.  If no expression follows the {lisp '}, DWIM gives up.{foot
{lisp '} is normally defined as a read-macro character which converts {lisp 'FOO} to {lisp (QUOTE FOO)} on input, so DWIM will not see the {lisp '} in the case of expressions that are typed-in.
}{comment endfootnote}
}


{Item
If {index CLISP}CLISP ({PageRef Tag CLISP}) is enabled, and the atom is part of a CLISP construct, the CLISP transformation is performed and the result returned.  For example, {lisp N-1} is transformed to {lisp (SUB1 N)}, and {lisp ({ellipsis} FOO←3 {ellipsis})} is transformed into {lisp ({ellipsis} (SETQ FOO 3) {ellipsis})}.
}

{Item
If the atom contains an {lisp 8} (actually {var LPARKEY}, see {PageRef Var LPARKEY}), DWIM assumes the {lisp 8} was intended to be a left parenthesis, and calls the editor to make appropriate repairs on the expression containing the atom.{index 8 (instead of left parenthesis)}  DWIM assumes that the user did not notice the mistake, i.e., that the entire expression was affected by the missing left parenthesis.  For example, if the user types {lisp (SETQ X (LIST (CONS 8CAR Y) (CDR Z)) Y)}, the expression will be changed to {lisp (SETQ X (LIST (CONS (CAR Y) (CDR Z)) Y))}.  Note that the {lisp 8} does not have to be the first character of the atom:  DWIM will handle {lisp (CONS X8CAR Y)} correctly.
}

{Item
If the atom contains a {lisp 9} (actually {var RPARKEY}, see {PageRef Var RPARKEY}), DWIM assumes the {lisp 9} was intended to be a right parenthesis and operates as in the case above.{index 9 (instead of right parenthesis)}
}

{Item
If the atom begins with a {lisp 7},{index 7 (instead of ')} the {lisp 7} is treated as a {lisp '}.  For example, {lisp 7FOO} becomes {lisp 'FOO}, and then {lisp (QUOTE FOO)}.

{note why no special variable like RPARKEY??}
}

{Item
If the atom is an edit command (a member of {index EDITCOMSA Var}{var EDITCOMSA}), and the error occurred in type-in, the effect is the same as though the user typed {lisp EDITF()}, followed by the atom, i.e., DWIM assumes the user wants to be in the editor editing the last thing he referred to.
Thus, if the user defines the function {lisp FOO} and then types {editcom P}, he will see {lisp =FOO}, followed by {lisp EDIT}, followed by the printout associated with the execution of the {lisp P} command, followed by {lisp *}, at which point he can continue editing {lisp FOO}.
}

{Item
The expressions on {var DWIMUSERFORMS}{index DWIMUSERFORMS Var} (see {PageRef Var DWIMUSERFORMS}) are evaluated in the order that they appear.  If any of these expressions returns a non-{lisp NIL} value, this value is treated as the form to be used to continue the computation, it is evaluated and its value is returned by {lisp DWIM}.
}

{Item
If the unbound atom occurs in a function, DWIM attempts spelling correction using the {lisp LAMBDA} and {fn PROG} variables of the function as the spelling list.
}

{Item
If the unbound atom occurred in a type-in to a break, DWIM attempts spelling correction using the {lisp LAMBDA} and {fn PROG} variables of the broken function as the spelling list.
}

{Item
Otherwise, DWIM attempts spelling correction using {index SPELLINGS3 Var}{var SPELLINGS3} (see {PageRef Var SPELLINGS3}).
}

{Item
If all of the above fail, DWIM gives up.
}


{End NumberedList Unbound Atoms}


{note how does CLISP get called to transform (ADD1 A+B) ==> (ADD1 (IPLUS A B)) ???}


}{End SubSec DWIM Correction: Unbound Atoms}


{Begin SubSec Undefined CAR of Form}
{Title Undefined CAR of Form}
{Text


If DWIM is called as the result of an undefined {fn CAR} of form error, it proceeds as follows:

{Begin NumberedList Undefined CAR of Form}

{Item
If {fn CAR} of the form is {lisp T}, DWIM assumes a misplaced {lisp T} clause
and operates as described on {PageRef Tag DWIMU.D.F.T}.
}

{Item
If {fn CAR} of the form is {lisp F/L},{index F/L (as a DWIM construct)} DWIM changes the "{lisp F/L}" to "{lisp FUNCTION(LAMBDA}".  For example, {lisp (F/L (Y) (PRINT (CAR Y)))} is changed to {lisp (FUNCTION (LAMBDA (Y) (PRINT (CAR Y)))}.  No message is printed and no approval requested.
If the user omits the variable list, DWIM supplies {lisp (X)}, e.g., {lisp (F/L (PRINT (CAR X)))} is changed to {lisp (FUNCTION (LAMBDA (X) (PRINT (CAR X))))}.  DWIM determines that the user has supplied the variable list when more than one expression follows {lisp F/L}, {fn CAR} of the first expression is not the name of a function, and every element in the first expression is atomic.
For example, DWIM will supply {lisp (X)} when correcting {lisp (F/L (PRINT (CDR X)) (PRINT (CAR X)))}.
}

{Item
If {fn CAR} of the form is a CLISP word{index CLISP words} ({lisp IF}, {lisp FOR}, {lisp DO}, {lisp FETCH}, etc.), the indicated CLISP transformation is performed, and the result is returned as the corrected form.  See {PageRef Tag CLISP}.
}

{Item
If {fn CAR} of the form has a function definition, DWIM attempts spelling correction on {fn CAR} of the definition using as spelling list the value of {var LAMBDASPLST}{index LAMBDASPLST Var}{index spelling lists}, initially {lisp (LAMBDA NLAMBDA)}.
}

{Item
If {fn CAR} of the form has an {index EXPR Prop}{prop EXPR} or {prop CODE} property, DWIM prints {lisp {arg CAR-OF-FORM} UNSAVED},{index UNSAVED (Printed by DWIM)} performs an {index UNSAVEDEF FN}{fn UNSAVEDEF}, and continues.  No approval is requested.
}

{Item
If {fn CAR} of the form has a {prop FILEDEF} property,{index *PRIMARY* FILEDEF Prop} the definition is loaded from a file.{foot
except when {fn DWIMIFY}ing.
}{comment endfootnote}
If the value of the property is atomic, the entire file is to be loaded.  If the value is a list, {fn CAR} is the name of the file and {fn CDR} the relevant functions, and {fn LOADFNS} will be used.  For both cases, {arg LDFLG} will be {index SYSLOAD (LOAD option)}{lisp SYSLOAD} (see {PageRef (LOAD option) SYSLOAD}).  DWIM uses {fn FINDFILE} ({PageRef Fn FINDFILE}), so that the file can be on any of the directories on {var DIRECTORIES}, initially {lisp (NIL NEWLISP LISP LISPUSERS)}.  If the file is found, DWIM types {lisp SHALL I LOAD}{index SHALL I LOAD Var} followed by the file name or list of functions.  If the user approves, DWIM loads the function(s) or file, and continues the computation.
}

{Item
If {index CLISP}CLISP is enabled, and {fn CAR} of the form is part of a CLISP construct, the indicated transformation is performed, e.g., {lisp (N←N-1)} becomes
{lisp (SETQ N (SUB1 N))}.
}

{Item
If {fn CAR} of the form contains an {lisp 8},{index 8 (instead of left parenthesis)} DWIM assumes a left parenthesis was intended
e.g., {lisp (CONS8CAR X)}.
}

{Item
If {fn CAR} of the form contains a {lisp 9},{index 9 (instead of right parenthesis)} DWIM assumes a right parenthesis was intended.
}

{Item
If {fn CAR} of the form is a list, DWIM attempts spelling correction on {fn CAAR} of the form using {var LAMBDASPLST}{index LAMBDASPLST Var}{index spelling lists} as spelling list.
If successful, DWIM returns the corrected expression itself.
}

{Item
If {fn CAR} of the form is a small number, and the error occurred in type-in, DWIM assumes the form is really an edit command and operates as described for unbound atom errors above.
}

{Item
If {fn CAR} of the form is an edit command (a member of {index EDITCOMSL Var}{var EDITCOMSL}), DWIM operates as in the previous case.
}

{Item
The expressions on {var DWIMUSERFORMS}{index DWIMUSERFORMS Var} are evaluated in the order they appear.  If any returns a non-{lisp NIL} value, this value is treated as the corrected form, it is evaluated, and {lisp DWIM} returns its value.
}

{Item
Otherwise, DWIM attempts spelling correction using {index SPELLINGS2 Var}{var SPELLINGS2} as the spelling list (see {PageRef Var SPELLINGS2}).  When {fn DWIMIFY}ing, {lisp DWIM} also attemps spelling correction on function names not defined but previously encountered, using {var NOFIXFNSLST} as a spelling list (see {PageRef Var NOFIXFNSLST}).
}

{Item
If all  of the above fail, DWIM gives up.
}

{End NumberedList Undefined CAR of Form}

}{End SubSec Undefined CAR of Form}






{Begin SubSec Undefined Function in APPLY}
{Title Undefined Function in APPLY}
{Text


If DWIM is called as the result of an undefined function in {fn APPLY} error, it proceeds as follows:


{Begin Numberedlist Undefined Function in APPLY}

{Item
If the function has a definition, DWIM attempts spelling correction on {fn CAR} of the definition using {var LAMBDASPLST} as spelling list.
}

{Item
If the function has an {index EXPR Prop}{prop EXPR} or {prop CODE} property, DWIM prints {lisp {arg FN} UNSAVED},{index UNSAVED (Printed by DWIM)} performs an {index UNSAVEDEF FN}{fn UNSAVEDEF} and continues.
No approval is requested.
}

{Item
If the function has a property {index FILEDEF Prop}{prop FILEDEF}, DWIM proceeds as in case 6 of undefined {fn CAR} of form.
}

{Item
If the error resulted from type-in, and CLISP is enabled, and the function
name contains a {index CLISP}CLISP operator, DWIM performs the indicated transformation, e.g., the user types {lisp FOO←(APPEND FIE FUM)}.
}

{Item
If the function name contains an {lisp 8},{index 8 (instead of left parenthesis)} DWIM assumes a left parenthesis was intended, e.g., {lisp EDIT8FOO]}.
}

{Item
If the "function" is a list, DWIM attempts spelling correction on {fn CAR} of the list using {var LAMBDASPLST}{index LAMBDASPLST Var} as spelling list{index spelling lists}.
}

{Item
If the function is a number and the error occurred in type-in, DWIM assumes the function is an edit command, and operates as described in case 6 of unbound atoms, e.g., the user types (on one line) {lisp 3 -1 P}.
}

{Item
If the function is the name of an edit command (on either {index EDITCOMSA Var}{var EDITCOMSA} or {index EDITCOMSL Var}{var EDITCOMSL}), DWIM operates as in the previous case, e.g., user types {lisp F COND}.
}

{Item
The expressions on {var DWIMUSERFORMS}{index DWIMUSERFORMS Var} are evaluated in the order they appear, and if any returns a non-{lisp NIL} value,
this value is treated as the function used to continue the computation, i.e., it will be applied to its arguments.
}

{Item
DWIM attempts spelling correction using {index SPELLINGS1 Var}{var SPELLINGS1} as the spelling list.
}

{Item
DWIM attempts spelling correction using {index SPELLINGS2 Var}{var SPELLINGS2} as the spelling list.
}

{Item
If all fail, DWIM gives up.
}

{End Numberedlist Undefined Function in APPLY}

}{End SubSec Undefined Function in APPLY}



{index *END* unbound atom}
{index *END* undefined function}


}{End SubSec DWIM Operation}




{Begin SubSec DWIMUSERFORMS}
{Title DWIMUSERFORMS}
{Text

{index *PRIMARY* DWIMUSERFORMS Var}

The variable {var DWIMUSERFORMS} provides a convenient way of adding to the transformations that DWIM performs.  For example, the user might want to change atoms of the form {lisp $X} to {lisp (QA4LOOKUP X)}.
Before attempting spelling correction, but after performing other transformations ({lisp F/L}, {lisp 8}, {lisp 9}, CLISP, etc.), DWIM evaluates the expressions on {var DWIMUSERFORMS} in the order they appear.  If any expression returns a non-{lisp NIL} value, this value is treated as the transformed form to be used.  If DWIM was called from {index FAULTEVAL FN}{fn FAULTEVAL}, this form is evaluated and the resulting value is returned as the value of {fn FAULTEVAL}.  If DWIM is called from {index FAULTAPPLY FN}{fn FAULTAPPLY}, this form is treated as a function to be applied to {lisp FAULTARGS}, and the resulting value is returned as the value of {fn FAULTAPPLY}.  If all of the expressions on {var DWIMUSERFORMS} return {lisp NIL}, DWIM proceeds as though {var DWIMUSERFORMS}={lisp NIL}, and attempts spelling correction.  Note that DWIM simply takes the value and returns it; the expressions on {var DWIMUSERFORMS} are responsible for
making any modifications to the original expression.{foot
The expressions on {var DWIMUSERFORMS} should make the transformation permanent, either by associating it with {lisp FAULTX} via {fn CLISPTRAN}, or by physically smashing {lisp FAULTX}.
}{comment endfootnote}


In order for an expression on {index DWIMUSERFORMS Var}{var DWIMUSERFORMS} to be able to be effective, it needs to know various things about the context of the error.  Therefore, several of DWIM's internal variables have been made {lisp SPECVARS} (see {PageRef Tag SPECVARS})
and are therefore "visible" to {var DWIMUSERFORMS}.
Below are a list of those variables that may be useful.

{index DWIM variables}

{VarDef {Name FAULTX}
{Text
For unbound atom and undefined car of form errors, {lisp FAULTX} is
the atom or form.  For undefined function in {fn APPLY} errors, {lisp FAULTX} is the name of the function.
}}


{VarDef {Name FAULTARGS}
{Text
For undefined function in {fn APPLY} errors, {lisp FAULTARGS} is the
list of arguments.  {lisp FAULTARGS} may be modified or reset by expressions on {var DWIMUSERFORMS}.
}}



{VarDef {Name FAULTAPPLYFLG}
{Text
Value is {lisp T} for undefined function in {fn APPLY} errors; {lisp NIL} otherwise.  The value of {lisp FAULTAPPLYFLG} {it after} an expression on {var DWIMUSERFORMS} returns a non-{lisp NIL} value determines how the latter value is to be treated.  Following an undefined function in {fn APPLY} error, if an expression on {var DWIMUSERFORMS} sets {lisp FAULTAPPLYFLG} to {lisp NIL}, the value returned is treated as a form to be evaluated, rather than a function to be applied.

{lisp FAULTAPPLYFLG} is necessary to distinguish between unbound atom and undefined function in {fn APPLY} errors, since {lisp FAULTARGS} may be {lisp NIL} and {lisp FAULTX} atomic in both cases.
}}


{VarDef {Name TAIL}
{Text
For unbound atom errors, {lisp TAIL} is the tail of the expression {fn CAR} of which is the unbound atom.  {var DWIMUSERFORMS} expression can replace the atom by another expression by performing {lisp (/RPLACA TAIL {arg EXPR})}
}}


{VarDef {Name PARENT}
{Text
For unbound atom errors, {lisp PARENT} is the form in which the unbound atom appears.  {lisp TAIL} is a tail of {lisp PARENT}.
}}


{VarDef {Name TYPE-IN?}
{Text
True if the error occurred in type-in.
}}


{VarDef {Name FAULTFN}
{Text
Name of the function in which error occurred.  {lisp FAULTFN} is {lisp TYPE-IN} when the error occurred in type-in, and {lisp EVAL} or {lisp APPLY} when the error occurred under an explicit call to {fn EVAL} or {fn APPLY}.
}}


{VarDef {Name DWIMIFYFLG}
{Text
True if the error was encountered while {fn DWIMIFY}ing (as opposed
to happening while running a program).
}}


{VarDef {Name EXPR}
{Text
Definition of {lisp FAULTFN}, or argument to {fn EVAL}, i.e., the
superform in which the error occurs.
}}


The initial value of {var DWIMUSERFORMS} is {lisp ((MACROTRAN) (DWIMLOADFNS?))}.  {index MACROTRAN FN}{fn MACROTRAN} is a package for running interpreted programs containing {lisp ASSEMBLE} statements or calls to "functions" defined only by {lisp MACRO} properties (see {PageRef Tag MACROTRAN}).  {fn DWIMLOADFNS?}{index DWIMLOADFNS? FN} is a function for automatically loading functions from files.  If {index DWIMLOADFNSFLG Var}{var DWIMLOADFNSFLG} is {lisp T} (its initial value), and {fn CAR} of the form is the name of a function, and the function is contained on a file that has been noticed by the file package, the function is loaded, and the computation continues.


}{End SubSec DWIMUSERFORMS}



{Begin SubSec DWIM Functions and Variables}
{Title DWIM Functions and Variables}
{Text



{VarDef {Name DWIMWAIT}
{Text
Value is the number of seconds that DWIM will wait before it assumes that the user is not going to respond to a question and uses the default response {var FIXSPELLDEFAULT}.

DWIM operates by dismissing for 250 milliseconds, then checking to see if anything has been typed.  If not, it dismisses again, etc. until {var DWIMWAIT} seconds have elapsed.  Thus, there will be a delay of at most 1/4 second before DWIM responds to the user's answer.
}}



{VarDef {Name FIXSPELLDEFAULT}
{Text
If approval is requested for a spelling correction, and user does not respond, defaults to value of {var FIXSPELLDEFAULT}, initially {lisp Y}.  {var FIXSPELLDEFAULT} is rebound to {lisp N} when {fn DWIMIFY}ing.
}}



{VarDef {Name ADDSPELLFLG}
{Text
If {lisp NIL}, suppresses calls to {fn ADDSPELL}.  Initially {lisp T}.

{note suppresses only calls from DWIM??}
}}



{index *PRIMARY* NOSPELLFLG Var}

{VarDef {Name NOSPELLFLG}
{Text
If {lisp T}, suppresses {it all} spelling correction.  If some other non-{lisp NIL} value, suppresses spelling correction in programs but not type-in.  {var NOSPELLFLG} is initially {lisp NIL}.  It is rebound to {lisp T} when compiling from a file.
}}



{VarDef {Name RUNONFLG}
{Text
If {lisp NIL}, suppresses run-on spelling corrections.  Initially {lisp T}.
}}



{VarDef {Name DWIMLOADFNSFLG}
{Text
If {lisp T}, tells DWIM that when it encounters a call to an undefined function contained on a file that has been noticed by the file package, to simply load the function.  {var DWIMLOADFNSFLG} is initially {lisp T}.  See {PageRef Fn DWIMLOADFNS?}.
}}



{VarDef {Name LPARKEY}}
{VarDef {Name RPARKEY}
{Text
DWIM uses the value of the variables {var LPARKEY} and {var RPARKEY} (initially {lisp 8} and {lisp 9} respectively) to determine the corresponding lower case character for left and right parentheses.  {var LPARKEY} and {var RPARKEY} can be reset for other keyboard layouts.{index keyboard layouts}, For example, on some terminals left parenthesis is over {lisp 9}, and right parenthesis is over {lisp 0}.
}}




{VarDef {Name OKREEVALST}
{Text
The value of {var OKREEVALST} is a list of functions that DWIM can safely reevaluate.  If a form is atomic, or {fn CAR} of the form is a member of {var OKREEVALST}, and each of the arguments can safely be reevaluated, then the form can be safely reevaluated.  For example, {lisp (SETQ X (CONS (IPLUS Y Z) W))} is safe to reevaluate because {fn SETQ}, {fn CONS}, and {fn IPLUS} are all on {var OKREEVALST}.

{note is this only used by DWIM in U.D.F. T Errors, or is it also used in other places??}
}}



{VarDef {Name DWIMFLG}
{Text
{var DWIMFLG}={lisp NIL}, all DWIM operations are disabled.  {lisp (DWIM 'C)} and {lisp (DWIM T)} set {var DWIMFLG} to {lisp T}; {lisp (DWIM NIL)} sets {var DWIMFLG} to {lisp NIL}.
}}



{VarDef {Name APPROVEFLG}
{Text
{var APPROVEFLG}={lisp T} if DWIM should ask the user for approval before making a correction that will modify the definition of one of his functions; {lisp NIL} otherwise.

When DWIM is put into {lisp CAUTIOUS} mode with {lisp (DWIM 'C)}, {var APPROVEFLG} is set to {lisp T}; for {lisp TRUSTING} mode, {var APPROVEFLG} is set to {lisp NIL}.
}}



{VarDef {Name LAMBDASPLST}
{Text
DWIM uses the value of {var LAMBDASPLST} as the spelling list when correcting "bad" function definitions.  Initially {lisp (LAMBDA NLAMBDA)}.  The user may wish to add to {var LAMBDASPLST} if he elects to define new "function types" via an appropriate {var DWIMUSERFORMS} entry.  For example, the {lisp QLAMBDA}s of SRI's QLISP are handled in this way.
}}


}{End SubSec DWIM Functions and Variables}