204 lines
16 KiB
HTML
204 lines
16 KiB
HTML
|
<!-- Common Lisp HyperSpec (TM), version 7.0 generated by Kent M. Pitman on Mon, 11-Apr-2005 2:31am EDT -->
|
||
|
<HTML>
|
||
|
<HEAD>
|
||
|
<TITLE>CLHS: Macro RESTART-CASE</TITLE>
|
||
|
<LINK HREF="../Data/clhs.css" REL="stylesheet" TYPE="text/css" />
|
||
|
<META HTTP-EQUIV="Author" CONTENT="Kent M. Pitman">
|
||
|
<META HTTP-EQUIV="Organization" CONTENT="LispWorks Ltd.">
|
||
|
<LINK REL=TOP HREF="../Front/index.htm">
|
||
|
<LINK REL=COPYRIGHT HREF="../Front/Help.htm#Legal">
|
||
|
<LINK REL=DISCLAIMER HREF="../Front/Help.htm#Disclaimer">
|
||
|
<LINK REL=PREV HREF="m_rst_bi.htm">
|
||
|
<LINK REL=UP HREF="c_condit.htm">
|
||
|
<LINK REL=NEXT HREF="f_rst_na.htm">
|
||
|
</HEAD>
|
||
|
<BODY>
|
||
|
<H1><A REV=MADE HREF="http://www.lispworks.com/"><IMG WIDTH=80 HEIGHT=65 ALT="[LISPWORKS]" SRC="../Graphics/LWSmall.gif" ALIGN=Bottom></A><A REL=TOP HREF="../Front/index.htm"><IMG WIDTH=237 HEIGHT=65 ALT="[Common Lisp HyperSpec (TM)]" SRC="../Graphics/CLHS_Sm.gif" ALIGN=Bottom></A> <A REL=PREV HREF="m_rst_bi.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="c_condit.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="f_rst_na.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
|
||
|
|
||
|
<HR>
|
||
|
|
||
|
<A NAME="restart-case"><I>Macro</I> <B>RESTART-CASE</B></A> <P>
|
||
|
<P>
|
||
|
<P><B>Syntax:</B><P>
|
||
|
<P>
|
||
|
|
||
|
<B>restart-case</B> <I>restartable-form {<I>clause</I>}</I> => <I><I>result</I><B>*</B></I><P>
|
||
|
<P>
|
||
|
<PRE>
|
||
|
clause::= (case-name lambda-list
|
||
|
[[:interactive interactive-expression | :report report-expression | :test test-expression]]
|
||
|
declaration* form*)
|
||
|
</PRE>
|
||
|
<P>
|
||
|
<P><B>Arguments and Values:</B><P>
|
||
|
<P>
|
||
|
<I>restartable-form</I>---a <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A>. <P>
|
||
|
<I>case-name</I>---a <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A> or <A REL=DEFINITION HREF="a_nil.htm#nil"><B>nil</B></A>. <P>
|
||
|
<I>lambda-list</I>---an <A REL=DEFINITION HREF="26_glo_o.htm#ordinary_lambda_list"><I>ordinary lambda list</I></A>. <P>
|
||
|
<I>interactive-expression</I>---a <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A> or a <A REL=DEFINITION HREF="26_glo_l.htm#lambda_expression"><I>lambda expression</I></A>. <P>
|
||
|
<I>report-expression</I>---a <A REL=DEFINITION HREF="26_glo_s.htm#string"><I>string</I></A>, a <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A>, or a <A REL=DEFINITION HREF="26_glo_l.htm#lambda_expression"><I>lambda expression</I></A>. <P>
|
||
|
<I>test-expression</I>---a <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A> or a <A REL=DEFINITION HREF="26_glo_l.htm#lambda_expression"><I>lambda expression</I></A>. <P>
|
||
|
<I>declaration</I>---a <A REL=DEFINITION HREF="s_declar.htm#declare"><B>declare</B></A> <A REL=DEFINITION HREF="26_glo_e.htm#expression"><I>expression</I></A>; not evaluated. <P>
|
||
|
<I>form</I>---a <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A>. <P>
|
||
|
<I>results</I>---the <A REL=DEFINITION HREF="26_glo_v.htm#value"><I>values</I></A> resulting from the <A REL=DEFINITION HREF="26_glo_e.htm#evaluation"><I>evaluation</I></A> of <I>restartable-form</I>, or the <A REL=DEFINITION HREF="26_glo_v.htm#value"><I>values</I></A> returned by the last <I>form</I> executed in a chosen <I>clause</I>, or <A REL=DEFINITION HREF="a_nil.htm#nil"><B>nil</B></A>. <P>
|
||
|
<P><B>Description:</B><P>
|
||
|
<P>
|
||
|
<A REL=DEFINITION HREF="#restart-case"><B>restart-case</B></A> evaluates <I>restartable-form</I> in a <A REL=DEFINITION HREF="26_glo_d.htm#dynamic_environment"><I>dynamic environment</I></A> where the clauses have special meanings as points to which control may be transferred. If <I>restartable-form</I> finishes executing and returns any values, all values returned are returned by <A REL=DEFINITION HREF="#restart-case"><B>restart-case</B></A> and processing has completed. While <I>restartable-form</I> is executing, any code may transfer control to one of the clauses (see <A REL=DEFINITION HREF="f_invo_1.htm#invoke-restart"><B>invoke-restart</B></A>). 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 <A REL=DEFINITION HREF="#restart-case"><B>restart-case</B></A>. In this case, the dynamic state is unwound appropriately (so that the restarts established around the <I>restartable-form</I> are no longer active) prior to execution of the clause. <P>
|
||
|
If there are no <I>forms</I> in a selected clause, <A REL=DEFINITION HREF="#restart-case"><B>restart-case</B></A> returns <A REL=DEFINITION HREF="a_nil.htm#nil"><B>nil</B></A>. <P>
|
||
|
If <I>case-name</I> is a <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A>, it names this restart. <P>
|
||
|
It is possible to have more than one clause use the same <I>case-name</I>. In this case, the first clause with that name is found by <A REL=DEFINITION HREF="f_find_r.htm#find-restart"><B>find-restart</B></A>. The other clauses are accessible using <A REL=DEFINITION HREF="f_comp_1.htm#compute-restarts"><B>compute-restarts</B></A>. <P>
|
||
|
Each <I>arglist</I> is an <A REL=DEFINITION HREF="26_glo_o.htm#ordinary_lambda_list"><I>ordinary lambda list</I></A> to be bound during the execution of its corresponding <I>forms</I>. These parameters are used by the <A REL=DEFINITION HREF="#restart-case"><B>restart-case</B></A> clause to receive any necessary data from a call to <A REL=DEFINITION HREF="f_invo_1.htm#invoke-restart"><B>invoke-restart</B></A>. <P>
|
||
|
By default, <A REL=DEFINITION HREF="f_invo_2.htm#invoke-restart-interactively"><B>invoke-restart-interactively</B></A> passes no arguments and all arguments must be optional in order to accomodate interactive restarting. However, the arguments need not be optional if the <TT>:interactive</TT> keyword has been used to inform <A REL=DEFINITION HREF="f_invo_2.htm#invoke-restart-interactively"><B>invoke-restart-interactively</B></A> about how to compute a proper argument list. <P>
|
||
|
<I>Keyword</I> options have the following meaning. <P><DL><DT><TT>:interactive</TT> <P><DD>
|
||
|
The <I>value</I> supplied by <TT>:interactive </TT><I>value</I><TT></TT> must be a suitable argument to <A REL=DEFINITION HREF="s_fn.htm#function"><B>function</B></A>. <TT>(function </TT><I>value</I><TT>)</TT> is evaluated in the current lexical environment. It should return a <A REL=DEFINITION HREF="26_glo_f.htm#function"><I>function</I></A> of no arguments which returns arguments to be used by <A REL=DEFINITION HREF="f_invo_2.htm#invoke-restart-interactively"><B>invoke-restart-interactively</B></A> when it is invoked. <A REL=DEFINITION HREF="f_invo_2.htm#invoke-restart-interactively"><B>invoke-restart-interactively</B></A> is called in the dynamic environment available prior to any restart attempt, and uses <A REL=DEFINITION HREF="26_glo_q.htm#query_iSLo"><I>query I/O</I></A> for user interaction. <P>
|
||
|
If a restart is invoked interactively but no <TT>:interactive</TT> option was supplied, the argument list used in the invocation is the empty list. <P>
|
||
|
<DT><TT>:report</TT> <P><DD>
|
||
|
If the <I>value</I> supplied by <TT>:report </TT><I>value</I><TT></TT> is a <A REL=DEFINITION HREF="26_glo_l.htm#lambda_expression"><I>lambda expression</I></A> or a <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A>, it must be acceptable to <A REL=DEFINITION HREF="s_fn.htm#function"><B>function</B></A>. <TT>(function </TT><I>value</I><TT>)</TT> is evaluated in the current lexical environment. It should return a <A REL=DEFINITION HREF="26_glo_f.htm#function"><I>function</I></A> of one argument, a <A REL=DEFINITION HREF="26_glo_s.htm#stream"><I>stream</I></A>, which prints on the <A REL=DEFINITION HREF="26_glo_s.htm#stream"><I>stream</I></A> a description of the restart. This <A REL=DEFINITION HREF="26_glo_f.htm#function"><I>function</I></A> is called whenever the restart is printed while <A REL=DEFINITION HREF="v_pr_esc.htm#STprint-escapeST"><B>*print-escape*</B></A> is <A REL=DEFINITION HREF="a_nil.htm#nil"><B>nil</B></A>. <P>
|
||
|
If <I>value</I> is a <A REL=DEFINITION HREF="26_glo_s.htm#string"><I>string</I></A>, it is a shorthand for <P>
|
||
|
<PRE>
|
||
|
(lambda (stream) (write-string value stream))
|
||
|
</PRE>
|
||
|
</TT> <P>
|
||
|
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. <P>
|
||
|
When <A REL=DEFINITION HREF="v_pr_esc.htm#STprint-escapeST"><B>*print-escape*</B></A> is <A REL=DEFINITION HREF="a_nil.htm#nil"><B>nil</B></A>, the printer uses the report information for a restart. For example, a debugger might announce the action of typing a ``continue'' command by: <P>
|
||
|
<PRE>
|
||
|
(format t "~&~S -- ~A~%" ':continue some-restart)
|
||
|
</PRE>
|
||
|
</TT> which might then display as something like: <P>
|
||
|
<PRE>
|
||
|
:CONTINUE -- Return to command level
|
||
|
</PRE>
|
||
|
</TT> <P>
|
||
|
The consequences are unspecified if an unnamed restart is specified but no <TT>:report</TT> option is provided. <P>
|
||
|
<DT><TT>:test</TT> <P><DD>
|
||
|
The <I>value</I> supplied by <TT>:test </TT><I>value</I><TT></TT> must be a suitable argument to <A REL=DEFINITION HREF="s_fn.htm#function"><B>function</B></A>. <TT>(function </TT><I>value</I><TT>)</TT> is evaluated in the current lexical environment. It should return a <A REL=DEFINITION HREF="26_glo_f.htm#function"><I>function</I></A> of one <A REL=DEFINITION HREF="26_glo_a.htm#argument"><I>argument</I></A>, the <A REL=DEFINITION HREF="26_glo_c.htm#condition"><I>condition</I></A>, that returns <A REL=DEFINITION HREF="26_glo_t.htm#true"><I>true</I></A> if the restart is to be considered visible. <P>
|
||
|
The default for this option is equivalent to <TT>(lambda (c) (declare (ignore c)) t)</TT>. <P></DL><P>
|
||
|
If the <I>restartable-form</I> is a <A REL=DEFINITION HREF="26_glo_l.htm#list"><I>list</I></A> whose <A REL=DEFINITION HREF="26_glo_c.htm#car"><I>car</I></A> is any of the <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbols</I></A> <A REL=DEFINITION HREF="f_signal.htm#signal"><B>signal</B></A>, <A REL=DEFINITION HREF="f_error.htm#error"><B>error</B></A>, <A REL=DEFINITION HREF="f_cerror.htm#cerror"><B>cerror</B></A>, or <A REL=DEFINITION HREF="f_warn.htm#warn"><B>warn</B></A> (or is a <A REL=DEFINITION HREF="26_glo_m.htm#macro_form"><I>macro form</I></A> which macroexpands into such a <A REL=DEFINITION HREF="26_glo_l.htm#list"><I>list</I></A>), then <A REL=DEFINITION HREF="m_w_cnd_.htm#with-condition-restarts"><B>with-condition-restarts</B></A> is used implicitly to associate the indicated <A REL=DEFINITION HREF="26_glo_r.htm#restart"><I>restarts</I></A> with the <A REL=DEFINITION HREF="26_glo_c.htm#condition"><I>condition</I></A> to be signaled. <P>
|
||
|
<P><B>Examples:</B><P>
|
||
|
<P>
|
||
|
<PRE>
|
||
|
(restart-case
|
||
|
(handler-bind ((error #'(lambda (c)
|
||
|
(declare (ignore condition))
|
||
|
(invoke-restart 'my-restart 7))))
|
||
|
(error "Foo."))
|
||
|
(my-restart (&optional v) v))
|
||
|
=> 7
|
||
|
|
||
|
(define-condition food-error (error) ())
|
||
|
=> FOOD-ERROR
|
||
|
(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 (lambda (condition stream)
|
||
|
(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)))))
|
||
|
=> BAD-TASTING-SUNDAE
|
||
|
(defun all-start-with-same-letter (symbol1 symbol2 symbol3)
|
||
|
(let ((first-letter (char (symbol-name symbol1) 0)))
|
||
|
(and (eql first-letter (char (symbol-name symbol2) 0))
|
||
|
(eql first-letter (char (symbol-name symbol3) 0)))))
|
||
|
=> ALL-START-WITH-SAME-LETTER
|
||
|
(defun read-new-value ()
|
||
|
(format t "Enter a new value: ")
|
||
|
(multiple-value-list (eval (read))))
|
||
|
=> READ-NEW-VALUE
|
||
|
(defun verify-or-fix-perfect-sundae (ice-cream sauce topping)
|
||
|
(do ()
|
||
|
((all-start-with-same-letter ice-cream sauce topping))
|
||
|
(restart-case
|
||
|
(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
|
||
|
(setq ice-cream new-ice-cream))
|
||
|
(use-new-sauce (new-sauce)
|
||
|
:report "Use a new sauce."
|
||
|
:interactive read-new-value
|
||
|
(setq sauce new-sauce))
|
||
|
(use-new-topping (new-topping)
|
||
|
:report "Use a new topping."
|
||
|
:interactive read-new-value
|
||
|
(setq topping new-topping))))
|
||
|
(values ice-cream sauce topping))
|
||
|
=> VERIFY-OR-FIX-PERFECT-SUNDAE
|
||
|
(verify-or-fix-perfect-sundae 'vanilla 'caramel 'cherry)
|
||
|
>> 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
|
||
|
=> CHOCOLATE, CARAMEL, CHERRY
|
||
|
</PRE>
|
||
|
</TT> <P>
|
||
|
<P><B>Side Effects:</B> None.
|
||
|
<P>
|
||
|
<P><B>Affected By:</B> None.
|
||
|
<P>
|
||
|
<P><B>Exceptional Situations:</B> None.
|
||
|
<P>
|
||
|
<P><B>See Also:</B><P>
|
||
|
<P>
|
||
|
<A REL=DEFINITION HREF="m_rst_bi.htm#restart-bind"><B>restart-bind</B></A>, <A REL=DEFINITION HREF="m_w_smp_.htm#with-simple-restart"><B>with-simple-restart</B></A>. <P>
|
||
|
<P><B>Notes:</B><P>
|
||
|
<P>
|
||
|
<PRE>
|
||
|
(restart-case expression
|
||
|
(name1 arglist1 ...options1... . body1)
|
||
|
(name2 arglist2 ...options2... . body2))
|
||
|
</PRE>
|
||
|
</TT> is essentially equivalent to <P>
|
||
|
<PRE>
|
||
|
(block #1=#:g0001
|
||
|
(let ((#2=#:g0002 nil))
|
||
|
(tagbody
|
||
|
(restart-bind ((name1 #'(lambda (&rest temp)
|
||
|
(setq #2# temp)
|
||
|
(go #3=#:g0003))
|
||
|
...slightly-transformed-options1...)
|
||
|
(name2 #'(lambda (&rest temp)
|
||
|
(setq #2# temp)
|
||
|
(go #4=#:g0004))
|
||
|
...slightly-transformed-options2...))
|
||
|
(return-from #1# expression))
|
||
|
#3# (return-from #1#
|
||
|
(apply #'(lambda arglist1 . body1) #2#))
|
||
|
#4# (return-from #1#
|
||
|
(apply #'(lambda arglist2 . body2) #2#)))))
|
||
|
</PRE>
|
||
|
</TT> <P>
|
||
|
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. <P>
|
||
|
|
||
|
<PRE>
|
||
|
(restart-case (signal fred)
|
||
|
(a ...)
|
||
|
(b ...))
|
||
|
==
|
||
|
(restart-case
|
||
|
(with-condition-restarts fred
|
||
|
(list (find-restart 'a)
|
||
|
(find-restart 'b))
|
||
|
(signal fred))
|
||
|
(a ...)
|
||
|
(b ...))
|
||
|
</PRE>
|
||
|
</TT> <P>
|
||
|
<P>
|
||
|
<P><HR>The following <A REL=META HREF="../Front/X3J13Iss.htm">X3J13 cleanup issues</A>, <I>not part of the specification</I>, apply to this section:<P><UL><LI> <A REL=CHILD HREF="../Issues/iss076.htm">CONDITION-RESTARTS:PERMIT-ASSOCIATION</A><LI> <A REL=CHILD HREF="../Issues/iss097.htm">DECLS-AND-DOC</A><P></UL><HR>
|
||
|
|
||
|
<A REL=NAVIGATOR HREF="../Front/StartPts.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Starting Points]" SRC="../Graphics/StartPts.gif" ALIGN=Bottom></A><A REL=TOC HREF="../Front/Contents.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Contents]" SRC="../Graphics/Contents.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Master.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Index]" SRC="../Graphics/Index.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Symbol.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Symbols]" SRC="../Graphics/Symbols.gif" ALIGN=Bottom></A><A REL=GLOSSARY HREF="../Body/26_a.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Glossary]" SRC="../Graphics/Glossary.gif" ALIGN=Bottom></A><A HREF="../Front/X3J13Iss.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Issues]" SRC="../Graphics/Issues.gif" ALIGN=Bottom></A><BR>
|
||
|
|
||
|
<A REL=COPYRIGHT HREF="../Front/Help.htm#Legal"><I>Copyright 1996-2005, LispWorks Ltd. All rights reserved.</I></A><P>
|
||
|
</BODY>
|
||
|
</HTML>
|