User Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cl:macros:restart-case [2019/09/14 05:00]
cl:macros:restart-case [2019/09/20 08:00] (current)
Line 1: Line 1:
 +====== Macro RESTART-CASE ======
 +
 +====Syntax====
 +  * **restart-case** //​restartable-form {clause}// → //​result''​*''//​
 +
 +<​blockquote>​
 +//clause// ::= (case-name lambda-list ​
 +<​nowiki> ​           [[</​nowiki>​**'':​interactive''​** interactive-expression | 
 +<​nowiki> ​             </​nowiki>​**'':​report''​** report-expression | 
 +<​nowiki> ​             </​nowiki>​**'':​test''​** test-expression<​nowiki>​]]</​nowiki>​
 +<​nowiki> ​           </​nowiki>​declaration''​*''​ form''​*''​) ​
 +</​blockquote>​
 +
 +====Arguments and Values====
 +  * //​restartable-form//​ - a //​[[CL:​Glossary:​form]]//​.
 +  * //​case-name//​ - a //​[[CL:​Glossary:​symbol]]//​ or **[[CL:​Constant Variables:​nil]]**.
 +  * //​lambda-list//​ - an //​[[CL:​Glossary:​ordinary lambda list]]//.
 +  * //​interactive-expression//​ - a //​[[CL:​Glossary:​symbol]]//​ or a //​[[CL:​Glossary:​lambda expression]]//​.
 +  * //​report-expression//​ - a //​[[CL:​Glossary:​string]]//,​ a //​[[CL:​Glossary:​symbol]]//,​ or a //​[[CL:​Glossary:​lambda expression]]//​.
 +  * //​test-expression//​ - a //​[[CL:​Glossary:​symbol]]//​ or a //​[[CL:​Glossary:​lambda expression]]//​.
 +  * //​declaration//​ - a **[[CL:​Symbols:​declare]]** //​[[CL:​Glossary:​expression]]//;​ not evaluated.
 +  * //form// - a //​[[CL:​Glossary:​form]]//​.
 +  * //results// - the //​[[CL:​Glossary:​values]]//​ resulting from the //​[[CL:​Glossary:​evaluation]]//​ of //​restartable-form//,​ or the //​[[CL:​Glossary:​values]]//​ returned by the last //form// executed in a chosen //​[[CL:​Glossary:​clause]]//,​ or **[[CL:​Constant Variables:​nil]]**.
 +
 +====Description====
 +**restart-case** evaluates //​restartable-form//​ in a //​[[CL:​Glossary:​dynamic environment]]//​ where the clauses have special meanings as points to which control may be transferred. If //​restartable-form//​ finishes executing and returns any values, all values returned are returned by **restart-case** and processing has completed. While //​restartable-form//​ is executing, any code may transfer control to one of the clauses (see **[[CL:​Functions:​invoke-restart]]**). If a transfer occurs, the forms in the body of that clause is evaluated and any values returned by the last such form are returned by **restart-case**. In this case, the dynamic state is unwound appropriately (so that the restarts established around the //​restartable-form//​ are no longer active) prior to execution of the clause.
 +
 +If there are no //forms// in a selected clause, **restart-case** returns **[[CL:​Constant Variables:​nil]]**.
 +
 +If //​case-name//​ is a //​[[CL:​Glossary:​symbol]]//,​ it names this restart.
 +
 +It is possible to have more than one clause use the same //​case-name//​. In this case, the first clause with that name is found by **[[CL:​Functions:​find-restart]]**. The other clauses are accessible using **[[CL:​Functions:​compute-restarts]]**.
 +
 +Each //arglist// is an //​[[CL:​Glossary:​ordinary lambda list]]// to be bound during the execution of its corresponding //forms//. These parameters are used by the **restart-case** clause to receive any necessary data from a call to **[[CL:​Functions:​invoke-restart]]**.
 +
 +By default, **[[CL:​Functions:​invoke-restart-interactively]]** passes no arguments and all arguments must be optional in order to accomodate interactive restarting. However, the arguments need not be optional if the **'':​interactive''​** keyword has been used to inform **[[CL:​Functions:​invoke-restart-interactively]]** about how to compute a proper argument list.
 +
 +//Keyword// options have the following meaning.
 +
 +===:​interactive===
 +The //value// supplied by '':​interactive //​value//''​ must be a suitable argument to **[[CL:​Special Operators:​function]]**. ''​([[CL:​Special Operators:​function]] //​value//​)''​ is evaluated in the current lexical environment. It should return a //​[[CL:​Glossary:​function]]//​ of no arguments which returns arguments to be used by **[[CL:​Functions:​invoke-restart-interactively]]** when it is invoked. **[[CL:​Functions:​invoke-restart-interactively]]** is called in the dynamic environment available prior to any restart attempt, and uses //​[[CL:​Glossary:​query IO|query IO]]// for user interaction.
 +
 +If a restart is invoked interactively but no **'':​interactive''​** option was supplied, the argument list used in the invocation is the empty list.
 +
 +===:​report===
 +If the //value// supplied by '':​report //​value//''​ is a //​[[CL:​Glossary:​lambda expression]]//​ or a //​[[CL:​Glossary:​symbol]]//,​ it must be acceptable to **[[CL:​Special Operators:​function]]**. ''​([[CL:​Special Operators:​function]] //​value//​)''​ is evaluated in the current lexical environment. It should return a //​[[CL:​Glossary:​function]]//​ of one argument, a //​[[CL:​Glossary:​stream]]//,​ which prints on the //​[[CL:​Glossary:​stream]]//​ a description of the restart. This //​[[CL:​Glossary:​function]]//​ is called whenever the restart is printed while **[[CL:​Variables:​star-print-escape-star|*print-escape*]]** is **[[CL:​Constant Variables:​nil]]**.
 +
 +If //value// is a //​[[CL:​Glossary:​string]]//,​ it is a shorthand for ''​([[CL:​Symbols:​lambda]] (stream) ([[CL:​Functions:​write-string]] //value// stream))''​.
 +
 +If a named restart is asked to report but no report information has been supplied, the name of the restart is used in generating default report text.
 +
 +When **[[CL:​Variables:​star-print-escape-star|*print-escape*]]** is **[[CL:​Constant Variables:​nil]]**,​ the printer uses the report information for a restart. For example, a debugger might announce the action of typing a "​continue"​ command by ''​([[CL:​Functions:​format]] [[CL:​Constant Variables:​t]] "​~&​~S -- ~A~%" ':​continue some-restart)''​ which might then display as something like '':​CONTINUE -- Return to command level''​.
 +
 +The consequences are unspecified if an unnamed restart is specified but no **'':​report''​** option is provided.
 +
 +===:test===
 +The //value// supplied by '':​test //​value//''​ must be a suitable argument to **[[CL:​Special Operators:​function]]**. ''​(function //​value//​)''​ is evaluated in the current lexical environment. It should return a //​[[CL:​Glossary:​function]]//​ of one //​[[CL:​Glossary:​argument]]//,​ the //​[[CL:​Glossary:​condition]]//,​ that returns //​[[CL:​Glossary:​true]]//​ if the restart is to be considered visible.
 +
 +The default for this option is equivalent to ''​([[CL:​Symbols:​lambda]] <​nowiki>​(c)</​nowiki>​ ([[CL:​Symbols:​declare]] ([[CL:​Declarations:​ignore]] c)) [[CL:​Constant Variables:​t]])''​.
 +
 +----
 +
 +If the //​restartable-form//​ is a //​[[CL:​Glossary:​list]]//​ whose //​[[CL:​Glossary:​car]]//​ is any of the //​[[CL:​Glossary:​symbols]]//​ **[[CL:​Functions:​signal]]**,​ **[[CL:​Functions:​error]]**,​ **[[CL:​Functions:​cerror]]**,​ or **[[CL:​Functions:​warn]]** (or is a //​[[CL:​Glossary:​macro form]]// which macroexpands into such a //​[[CL:​Glossary:​list]]//​),​ then **[[CL:​Macros:​with-condition-restarts]]** is used implicitly to associate the indicated //​[[CL:​Glossary:​restart|restarts]]//​ with the //​[[CL:​Glossary:​condition]]//​ to be signaled.
 +
 +====Examples====
 +<​blockquote>​
 +(restart-case
 +  ([[CL:​Macros:​handler-bind]] (([[CL:​Types:​error]] #'​([[CL:​Symbol:​lambda]] (c) ([[CL:​Symbols:​declare]] ([[CL:​Declaration:​ignore]] c))
 +                                      ([[Cl:​Functions:​invoke-restart]] '​my-restart 7))))
 +    ([[CL:​Functions:​error]] "​Foo."​))
 +  (my-restart (&​optional v) v)) <​r>​7</​r>​
 +
 +([[CL:​Macros:​define-condition]] food-error ([[CL:​Types:​error]]) ()) <​r>​FOOD-ERROR</​r>​
 +
 +([[CL:​Macros:​define-condition]] bad-tasting-sundae (food-error)
 +    ((ice-cream :initarg :​ice-cream ​
 +                :reader bad-tasting-sundae-ice-cream)
 +     ​(sauce :initarg :​sauce ​
 +            :reader bad-tasting-sundae-sauce)
 +     ​(topping :initarg :​topping ​
 +              :reader bad-tasting-sundae-topping))
 +  (:report ([[CL:​Symbol:​lambda]] (condition stream)
 +             ​([[CL:​Functions:​format]] stream "Bad tasting sundae with ~S, ~S, and ~S"
 +                     ​(bad-tasting-sundae-ice-cream condition)
 +                     ​(bad-tasting-sundae-sauce condition)
 +                     ​(bad-tasting-sundae-topping condition))))) <​r>​BAD-TASTING-SUNDAE</​r>​
 +
 +([[CL:​Macros:​defun]] all-start-with-same-letter (symbol1 symbol2 symbol3)
 +  ([[CL:​Special Operators:​let]] ((first-letter ([[CL:​Functions:​char]] ([[CL:​Functions:​symbol-name]] symbol1) 0)))
 +    ([[CL:​Macros:​and]] ([[CL:​Functions:​eql]] first-letter ([[CL:​Functions:​char]] ([[CL:​Functions:​symbol-name]] symbol2) 0))
 +         ​([[CL:​Functions:​eql]] first-letter ([[CL:​Functions:​char]] ([[CL:​Functions:​symbol-name]] symbol3) 0)))))
 +<​r>​ALL-START-WITH-SAME-LETTER</​r>​
 +
 +([[CL:​Macros:​defun]] read-new-value ()
 +  ([[CL:​Functions:​format]] [[CL:​Constant Variables:​t]] "Enter a new value: ")
 +  ([[CL:​Macros:​multiple-value-list]] ([[CL:​Functions:​eval]] ([[CL:​Functions:​read]]))))
 +<​r>​READ-NEW-VALUE</​r>​
 +  ​
 +([[CL:​Macros:​defun]] verify-or-fix-perfect-sundae (ice-cream sauce topping)
 +  ([[CL:​Macros:​do]] () ((all-start-with-same-letter ice-cream sauce topping))
 +    (restart-case ([[CL:​Functions:​error]] '​bad-tasting-sundae ​
 +                         :​ice-cream ice-cream :sauce sauce :topping topping)
 +      (use-new-ice-cream (new-ice-cream) ​
 +       :​report "Use a new ice cream."​
 +       :​interactive read-new-value
 +       ​([[CL:​Macros:​setf]] ice-cream new-ice-cream))
 +      (use-new-sauce (new-sauce)
 +       :​report "Use a new sauce."​
 +       :​interactive read-new-value
 +       ​([[CL:​Macros:​setf]] sauce new-sauce))
 +      (use-new-topping (new-topping)
 +       :​report "Use a new topping."​
 +       :​interactive read-new-value
 +       ​([[CL:​Macros:​setf]] topping new-topping))))
 +  ([[CL:​Functions:​values]] ice-cream sauce topping))
 +<​r>​VERIFY-OR-FIX-PERFECT-SUNDAE</​r>​
 +  ​
 +(verify-or-fix-perfect-sundae '​vanilla '​caramel '​cherry)
 +<​e>​Error:​ Bad tasting sundae with VANILLA, CARAMEL, and CHERRY.
 +To continue, type :CONTINUE followed by an option number:
 +1: Use a new ice cream.
 +2: Use a new sauce.
 +3: Use a new topping.
 +4: Return to Lisp Toplevel.
 +Debug> :continue 1
 +Use a new ice cream.
 +Enter a new ice cream: '​chocolate</​e>​
 +<​r>​CHOCOLATE
 +CARAMEL
 +CHERRY</​r>​
 +</​blockquote>​
 +
 +====Side Effects====
 +None.
 +
 +====Affected By====
 +None.
 +
 +====Exceptional Situations====
 +None.
 +
 +====See Also====
 +**[[CL:​Macros:​restart-bind|Macro RESTART-BIND]]**,​ **[[CL:​Macros:​with-simple-restart|Macro WITH-SIMPLE-RESTART]]**.
 +
 +====Notes====
 +<​blockquote>​
 +(restart-case ''​expression'' ​
 +  (''​name1''​ ''​arglist1''​ ...''​options1''​... . ''​body1''​)
 +  (''​name2''​ ''​arglist2''​ ...''​options2''​... . ''​body2''​))
 +</​blockquote>​
 +
 +is essentially equivalent to
 +
 +<​blockquote>​
 +([[CL:​Special Operators:​block]] #1=#:g0001
 +  ([[CL:​Special Operators:​let]] ((#​2=#:​g0002 [[CL:​Constant Variables:​nil]]))
 +    ([[CL:​Special Operators:​tagbody]]
 +     ​([[CL:​Macros:​restart-bind]] ((name1 #'​([[CL:​Symbols:​lambda]] (&rest temp)
 +                               ​([[CL:​Macros:​setf]] #2# temp)
 +                               (go #​3=#:​g0003))
 +                     ​...''​slightly-transformed-options1''​...)
 +                    (name2 #'​(lambda (&rest temp) 
 +                               ​([[CL:​Macros:​setf]] #2# temp)
 +                               (go #​4=#:​g0004))
 +                     ​...''​slightly-transformed-options2''​...))
 +       ​([[CL:​Special Operators:​return-from]] #1# ''​expression''​))
 +    #3# ([[CL:​Special Operators:​return-from]] #1# 
 +          ([[CL:​Functions:​apply]] #'​([[CL:​Symbols:​lambda]] ''​arglist1''​ . ''​body1''​) #2#))
 +    #4# ([[CL:​Special Operators:​return-from]] #1#
 +          ([[CL:​Functions:​apply]] #'​([[CL:​Symbols:​lambda]] ''​arglist2''​ . ''​body2''​) #2#)))))
 +</​blockquote>​
 +
 +Unnamed restarts are generally only useful interactively and an interactive option which has no description is of little value. Implementations are encouraged to warn if an unnamed restart is used and no report information is provided at compilation time. At runtime, this error might be noticed when entering the debugger. Since signaling an error would probably cause recursive entry into the debugger (causing yet another recursive error, etc.) it is suggested that the debugger print some indication of such problems when they occur but not actually signal errors.
 +
 +<​blockquote>​
 +(restart-case ([[CL:​Functions:​signal]] fred) (a ...) (b ...)) 
 +  ≡ (restart-case
 +        ([[CL:​Macros:​with-condition-restarts]] fred
 +            ([[CL:​Functions:​list]] ([[CL:​Functions:​find-restart]] 'a)
 +                  ([[CL:​Functions:​find-restart]] 'b))
 +          ([[CL:​Functions:​signal]] fred))
 +          (a ...)
 +          (b ...))
 +</​blockquote>​
 +
 +\issue{CONDITION-RESTARTS:​PERMIT-ASSOCIATION} \issue{DECLS-AND-DOC} \issue{CONDITION-RESTARTS:​PERMIT-ASSOCIATION} \issue{CONDITION-RESTARTS:​PERMIT-ASSOCIATION} \issue{CONDITION-RESTARTS:​PERMIT-ASSOCIATION}