-
Notifications
You must be signed in to change notification settings - Fork 2
/
srfi-249.html
301 lines (280 loc) · 16 KB
/
srfi-249.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<!DOCTYPE html>
<html lang="en">
<!--
SPDX-FileCopyrightText: Taylor Campbell, John Cowan
SPDX-License-Identifier: MIT
-->
<head>
<meta charset="utf-8">
<title>SRFI 249: Restarting conditions</title>
<link href="/favicon.png" rel="icon" sizes="192x192" type="image/png">
<link rel="stylesheet" href="https://srfi.schemers.org/srfi.css" type="text/css">
<meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
<h1><a href="https://srfi.schemers.org/"><img class="srfi-logo" src="https://srfi.schemers.org/srfi-logo.svg" alt="SRFI surfboard logo" /></a>249: Restarting conditions</h1>
<p>by Taylor Campbell (original text), John Cowan (revised text, shepherd), Wolfgang
Corcoran-Mathe (revised implementation), Arvydas Silanskas (initial
implementation)
</p>
<h2 id="status">Status</h2>
<p>This SRFI is currently in <em>withdrawn</em> status. Here is <a href="https://srfi.schemers.org/srfi-process.html">an explanation</a> of each status that a SRFI can hold. To provide input on this SRFI, please send email to <code><a href="mailto:srfi+minus+249+at+srfi+dotschemers+dot+org">srfi-249@<span class="antispam">nospam</span>srfi.schemers.org</a></code>. To subscribe to the list, follow <a href="https://srfi.schemers.org/srfi-list-subscribe.html">these instructions</a>. You can access previous messages via the mailing list <a href="https://srfi-email.schemers.org/srfi-249/">archive</a>.</p>
<ul>
<li>Received: 2023-11-11</li>
<li>Draft #1 published: 2023-11-13</li>
<li>Draft #2 published: 2024-09-13</li>
<li>Withdrawn (superseded by <a href="https://srfi.schemers.org/srfi-255/">SRFI 255</a>): 2024-09-13
<p>editor's summary of reasons for withdrawal: This SRFI was
withdrawn by the editor because there had been no progress
since 11-2023, and because he hadn't been able to reach the
author since 5-2024. Wolfgang Corcoran-Mathe volunteered to
take over with Marc Nieper-Wißkirchen.</p>
<p>Wolfgang wrote:</p>
<blockquote>
<p>Marc and I are working out an improved (I think) approach
to restarters which simplifies and corrects the semantics
of SRFI 249’s restart mechanism. It’s a major departure
from what’s described in SRFI 249, since it makes
restarters a new condition type and uses the Scheme
exception system rather than 249’s novel restarter stack.</p>
<p>As it stands, the system proposed by SRFI 249 is awkward to
integrate with the Scheme exception system. It adds a new
element to Scheme’s dynamic evaluation environment, a stack
of restarters, but does not provide a convenient way to use
this stack to recover from an exceptional situation: it
leaves the dirty work to the user. Nor is stack management
the full extent of the dirty work. SRFI 249 says nothing
about the control behavior of a restarter, leaving it to the
user of the library to ensure that a restarter’s invoker
actually returns the interrupted computation to a sane
situation. This is something that even the SRFI’s examples
failed to take into a account.</p></blockquote>
<p>A new SRFI was forked from this one
as <a href="https://srfi.schemers.org/srfi-255/">SRFI
255</a>.</p></li>
</ul>
<h2 id="abstract">Abstract</h2>
<p>When an exceptional situation is encountered by a program, it may
create a <em>condition</em> object describing the situation and then
signal the condition and pass control to a condition handler. The
signaler and handler are two different parts of a system, between which
there is a barrier of abstraction. In order to recover gracefully and
flexibly from exceptional situations, however, the signaler can provide
multiple ways by which the handler can restart the computation, some of
which may require extra input. Often, the decision of which method of
recovery to choose is left up to a human user, who may be prompted for
the input needed to recover. This SRFI proposes a simple mechanism
called <em>restarters</em> to encapsulate the information necessary to
restart a computation with associated interactive prompters.</p>
<h2 id="rationale">Rationale</h2>
<p>An effective and flexible system for gracefully handling and
recovering from exceptional situations is a necessity for any large
software system. Most condition or exception systems provide only a
one-way flow of information from the signaler to the handler, however:
they offer no way to communicate possible methods of recovery to the
signaler. Common Lisp, MIT Scheme, and Dylan are almost unique in this
regard: they provide comprehensive facilities for restarting in exceptional
situations. This proposal is considerably simpler than Common Lisp’s or
Dylan’s restart systems, more in the spirit of Scheme, however. It is
historically related to MIT Scheme’s system.</p>
<p>One important feature for a restart system to provide is
interactivity. Though purely programmatic condition recovery is useful,
it is well-acknowledged by the designers and users of Common Lisp’s
condition system that the ability to <em>interactively</em> choose a
method of recovery for a condition is useful. This ability, built-in to the Common
Lisp language, is one of the primary reasons for the power of Common
Lisp development and debugging environments. Though much of the baggage
in Common Lisp’s restart system was deemed unnecessary for this
proposal, interactivity is one crucial feature that was included. In
this SRFI, the interactivity is provided by an <em>interactor
procedure</em> that by default is provided by the implementation, but
can be overridden by the user.</p>
<p>One major difference between the CL and Scheme condition systems is
that when a CL handler exits to its caller, the next outer handler is
invoked, whereas when a Scheme handler exits, either the code that
raised the condition is resumed (if <code>raise-continuably</code> was
used), or another error is signaled (if <code>raise</code> was used);
the condition must be re-raised in order to give the next outer handler
control. Therefore, in CL the only way for the signaler to regain
control is through a restart, but in Scheme restarts are just one way of
handling returns from exceptions.</p>
<h2 id="specification">Specification</h2>
<p>A <em>restarter</em> is an object of a new disjoint type with three
fields:</p>
<ul>
<li><em>tag</em> - a symbol identifying this restarter</li>
<li><em>description</em> - a list of strings that describes the method
of recovery and the values, if any, needed for recovery</li>
<li><em>invoker</em> - a procedure that actually performs the recovery;
the number of arguments it expects is equal to the length of
<em>description</em> minus 1.</li>
</ul>
<p>Restarters can be available in one of two ways. They can be
<em>ambient restarters</em>, each of which is available during some
dynamic extent of the program, or they can be the value of some variable
or part of some data structure.</p>
<h3 id="procedures">Procedures</h3>
<p><code>(make-restarter </code><em>tag description
invoker</em><code>)</code> → <em>restarter</em></p>
<p>Returns a restarter with the specified tag, description, and
invoker.</p>
<p>The <em>tag</em> argument is a symbol.</p>
<p>The <em>description</em> argument is a list whose car is a string
that describes the effect of invoking the restarter. By convention it is
a complete sentence in a natural language using the standard punctuation
conventions of that language. It may also be a question or a command.
The cdr of <em>description</em> is a list of strings that describe the
values to be passed to the invoker in the same natural language: they
may be phrases or whole sentences.</p>
<p>The <em>invoker</em> argument is a recovery procedure.</p>
<p><code>(restarter? </code><em>obj</em><code>)</code> →
<em>boolean</em></p>
<p>Returns <code>#t</code> if <em>obj</em> is a restarter and
<code>#f</code> otherwise.</p>
<p>Examples:</p>
<pre><code>(restarter? return-zero-restarter) → #t
(restarter? 20) → #f</code></pre>
<p><code>(restarter-tag </code><em>restarter</em><code>)</code> →
<em>tag</em><br />
<code>(restarter-description </code><em>restarter</em><code>)</code> →
<em>list-of-strings</em></p>
<p>Returns the tag / description of <em>restarter</em>. It is an error
to mutate <em>list-of-strings</em> or any of its members.</p>
<p><code>(restart </code><em>restarter arg</em> …<code>)</code> →
<em>values</em> (may not return)</p>
<p>Invokes the invoker procedure of <em>restarter</em> on the
<em>args</em>, and returns however many values the invoker does. If the
invoker does not return, <code>restart</code> does not return
either.</p>
<p>Invoking the <code>return-zero</code> restarter:</p>
<pre><code>(restart return-zero) → 0</code></pre>
<p><code>(ambient-restarters)</code></p>
<p>Returns the current list of ambient restarters created by
<code>make-restarter</code> and established by
<code>with-restarter</code>. It is an error to mutate this list.
<code>Ambient-restarters</code> is normally a SRFI 39 / R7RS parameter,
but directly modifying it with <code>parameterize</code> should be
avoided.</p>
<p><code>(with-restarters </code><em>restarters
thunk</em><code>)</code></p>
<p>Establishes <em>restarters</em>, which may be a single restarter, a
list of restarters, or a SRFI 222 compound object, as ambient restarters
on top of the existing ambient restarters. It is an error if any of the
restarters specified by <em>restarters</em> have the same tag. Then
<code>with-restarter</code> invokes <em>thunk</em> with no arguments,
after which the restarters are disestablished and
<code>with-restarter</code> returns whatever <em>thunk</em> returns.</p>
<p><code>(find-restarter </code><em>tag restarters</em><code>)</code> →
<em>restarter</em> or <code>#f</code></p>
<p>Searches <em>restarters</em> for a restarter whose tag is the same
(in the sense of <code>symbol=?</code>) as <em>tag</em>. The
<em>restarters</em> argument may be a single restarter, a list of
restarters, or a <a
href="https://srfi.schemers.org/srfi-222/srfi-222.html">SRFI 222</a>
compound object. If no such restarter is found in <em>restarters</em>,
the value of <code>(ambient-restarters)</code> is searched instead.
Failing that as well, <code>#f</code> is returned.</p>
<p><code>(collect-restarters </code><em>restarters</em><code>)</code></p>
<p>The argument <em>restarters</em> has the same semantics as the
<em>restarters</em> argument of <code>find-restarter</code>. All
available restarters are collected into a list which is then returned,
giving the restarters in <em>restarters</em> priority over the
restarters in <code>(ambient-restarters)</code>, but excluding those
whose tag is the same (in the sense of <code>symbol=?</code>) as a
higher-priority restarter already on the list. Note that if
<em>restarters</em> is a list, earlier elements in the list take
priority over later ones, and the same is true for subobjects in a
compound object.</p>
<p><code>interactor</code></p>
<p>A SRFI 39 / R7RS parameter whose value is an interactor procedure.
The general contract of such a procedure is as follows:</p>
<p>It accepts one argument, a list of restarters. The tags and the cars
of the descriptions of the restarters are made available to the user.
The user is then allowed to choose one of the tags.<br />
Then the remaining strings in the description of the chosen restarter
are made available to the user, and the user is allowed to specify a
value corresponding to each string.</p>
<p>The interactor then calls <code>restart</code> on the restarter and
the user’s values and returns whatever <code>restart</code> returns.</p>
<p>The sample interactor outputs the tags and description strings with
<code>display</code> and reads the chosen tag and values using
<code>read</code>. Here is a possible example of the interaction:</p>
<pre><code>The following actions are available:
return-zero: Return zero.
return-numerator: Return the numerator.
use-value: Choose a value to return.
abort: Abort the computation.
Which action do you choose: use-value
What is the value you wish to use? 32</code></pre>
<p>In this case the restarter will return 32.</p>
<p><code>(restart-interactively </code><em>restarters</em><code>)</code>
→ <em>values</em> (may not return)</p>
<p>Equivalent to
<code>((interactor) (collect-restarters </code><em>restarters</em><code>))</code></p>
<h3 id="standard-restart-tags">Standard restart tags</h3>
<p>The following tags by convention hold to particular behaviour
protocols:</p>
<p><code>abort</code></p>
<p>Completely aborts the computation, usually returning to some sort of
initial user input such as a REPL. The invoker of an <code>abort</code>
restarter accepts zero arguments, is typically an ambient restarter, and
normally does not return.</p>
<p><code>ignore</code></p>
<p>Ignores the condition and proceeds. The invoker of an
<code>ignore</code> restarter accepts zero arguments, is typically an
ambient restarter, and normally returns an unspecified value.</p>
<p><code>retry</code></p>
<p>Simply retries a whole computation from a certain point, with no
explicitly altered inputs. Some implicit environmental changes are
expected to have taken place. The invoker of a <code>retry</code>
restarter accepts zero arguments, may or may not be an ambient
restarter, and normally returns an unspecified value.</p>
<p><code>use-value</code></p>
<p>Retries a computation with a given input value substituted for some
invalid value in the original input. The invoker of a
<code>use-value</code> restarter accepts at least one argument, the new
value(s) to substitute. It is may or may not be an ambient restarter,
and normally returns an unspecified value.</p>
<p><code>store-value</code></p>
<p>These restarter tag is in every respect like <code>use-value</code>
restarters except that it is meant to store the input value somewhere,
so that the old one is completely replaced, rather than just using the
input value temporarily and possibly accidentally reusing the old value
later and signaling another error.</p>
<h2 id="additional-recommendations">Additional recommendations</h2>
<p>It is highly recommended that Scheme systems integrate restarters
into their condition systems and debuggers. This can be achieved by
using SRFI 222 compound objects to represent conditions, with restarters
as members to represent suitable recovery strategies among the
subobjects.</p>
<h2 id="implementation">Implementation</h2>
<p>The implementation is available at
<a href="https://github.com/scheme-requests-for-implementation/srfi-249">Github</a>.
<h2 id="acknowledgements">Acknowledgements</h2>
<p>This SRFI is based on
<a href="restart.text">a proposal</a> by Taylor Campbell.</p>
<h2 id="copyright">Copyright</h2>
<p>© 2023 Taylor Campbell, John Cowan, Wolfgang
Corcoran-Mathe), Arvydas Silanskas.</p>
<p>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:</p>
<p>
The above copyright notice and this permission notice (including the
next paragraph) shall be included in all copies or substantial
portions of the Software.</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.</p>
<hr>
<address>Editor: <a href="mailto:srfi-editors+at+srfi+dot+schemers+dot+org">Arthur A. Gleckler</a></address></body></html>