-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsrfi-184.html
348 lines (293 loc) · 15.1 KB
/
srfi-184.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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>SRFI 184: define-record-lambda</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/srfi.css" type="text/css" />
<link href="/favicon.png" rel="icon" sizes="192x192" type="image/png" />
<style>
dt {
font-family: monospace;
margin: 0.5em 0;
}
em {
font-family: serif;
font-size: 120%;
}
.references a {
display: block;
margin: 0.5em 0;
}
.references td:first-child {
vertical-align: top;
width: 5em;
}
</style>
</head>
<body>
<h1>Title</h1>
define-record-lambda
<h1>Author</h1>
Joo ChurlSoo
<h1>Status</h1>
<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+184+at+srfi+dotschemers+dot+org">srfi-184@<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-184">archive</a>.</p>
<ul>
<li>Received: 2020-02-21</li>
<li>Draft #1 published: 2020-02-22</li>
<li>Withdrawn: 2020-03-27</li>
</ul>
<h1>Abstract</h1>
<p>This SRFI introduces a macro, DEFINE-RECORD-LAMBDA, that defines a
set of procedures, that is, a group of constructors and a predicate.
The constructors also make a group of procedures, namely record
lambdas, that have no explicit field accessors and mutators. They
can have various kinds of fields, such as common fields, required
fields, optional fields, automatic fields, read-only fields,
read-write fields, invisible fields, immutable fields, and virtual
fields.</p>
<h1>Changes from SRFI 100</h1>
<p>This SRFI is based on <a href="https://srfi.schemers.org/srfi-100/">SRFI
100</a>. Unlike the define-lambda-object of SRFI 100:</p>
<ol>
<li>The inheritance property has been removed because it was
ineffective and superfluous.</li>
<li>The record lambda uses field indices or symbolized field names
to identify fields according to the constructors.</li>
<li>The field sequence has been changed.</li></ol>
<h1>Rationale</h1>
<p>A record lambda created by a constructor procedure is a procedure
whose first argument is a field index or symbolized field name that
is used to identify fields. It depends on the constructor. The
record lambda plays the role of the accessor and mutator of each
field and makes the explicit or implicit accessors and mutators
unnecessary. In addition, this reduces the role of the predicate
procedure.</p>
<p>This macro works not only as DEFINE-RECORD-TYPE with required
fields but also as DEFSTRUCT of Common Lisp with optional fields.
Each field except required fields can be used as a procedure that
changes the values of the other fields. As a result, the record
lambda itself has data and methods as well as their accessors and
mutators.</p>
<h1>Specification</h1>
<pre>
(define-record-lambda <group> <field spec>)
<field spec> --> <common field>* <required field>* <optional field>* <automatic field>*
<common field> -->
| (,@<field> <default>) ;read-only automatic common field
| ((,@<field>) <default>) ;read-write automatic common field
| (',@<field> <default>) ;immutable automatic common field
| (`,@<field> <default>) ;invisible automatic common field
<required field> -->
| <field> ;read-only required field
| (<field>) ;read-write required field
| 'field ;immutable required field
| `field ;invisible required field
<optional field> -->
| (<field> <default>) ;read-only optional field
| ((<field>) <default>) ;read-write optional field
| ('<field> <default>) ;immutable optional field
| (`<field> <default>) ;invisible optional field
<automatic field> -->
| (,<field> <default>) ;read-only automatic field
| ((,<field>) <default>) ;read-write automatic field
| (',<field> <default>) ;immutable automatic field
| (`,<field> <default>) ;invisible automatic field
| (,,<field> <default>) ;virtual automatic field
</pre>
<p>The name of the first <constructor> is generated by prefixing "make-" to the
group name, or by prefixing "make-" and postfixing "-by-name" to the group
name. And the name of the second <constructor> is generated by appending "/s"
to the name of the first <constructor>.
While the record lambda that is constructed by the former uses field indices
to identify the fields, the one constructed by the latter uses
symbols. And the average time required to access a randomly chosen
field is more for the record lambda that is constructed by the latter
than for the one by the former.</p>
<p>The name of <predicate> is generated by adding a question mark ("?") to the
end of the group name.</p>
<p>The <group> and <field> must be identifiers.</p>
<p>Each <default> is an <expression> that is evaluated in
an environment in which the values of all the previous <field>s
are visible.</p>
<p>The define-record-lambda form is a definition and can appear anywhere any
other <definition> can appear. Each time define-record-lambda form is
evaluated, a new group is created with distinct <group>, <constructor>, and
<predicate> procedures.</p>
<p>The <group> is bound to a procedure of one argument. It has information on
its <constructor>s, <predicate>, and <field>s.</p>
<p>The <constructor> is bound to a procedure that takes at least as many
arguments as the number of <required field>s. Whenever it is called, it
returns a record lambda of the <group>, namely a procedure. Its first
argument must be a symbol of the same name as <field> or a field index whose
name is composed of the group name and field name. The record lambda becomes
an accessor procedure of each <field> in case of one argument and a mutator
procedure of each <field> in case of two arguments where the second argument
is a new field value.</p>
<p>The names of <field>s are used to access the <field>s. So they must be
distinct. The read-write fields can be modified, whereas any attempt to
modify the values of the read-only fields via mutators signals an error.</p>
<p>Note: The read-only fields are not immutable.
Their values, for instance, can be modified by other fields whose values
work like their mutators.</p>
<p>The <required field> is initialized to the first one of the remaining
arguments. If there are no more remaining arguments, an error is signaled.</p>
The initialization of the <optional field>s is done by two types of
<constructor>s:
<dl>
<dt>1. <make-<em>group-name</em>> constructor</dt>
<dd>The initialization method of <optional field>s is the same as that of
<required field>s except that the field is bound to the <default> instead of
signaling an error if there are no more remaining arguments.</dd>
<dt>2. <make-<em>group-name</em>-by-name> constructor</dt>
<dd>The name used at a call site for the corresponding <optional field> is a
symbol of the same name as the <field>. The remaining arguments are
sequentially interpreted as a series of pairs, where the first member of each
pair is a field name and the second is the corresponding value. If there is
no element for a particular field name, the field is initialized to the
<default>.</dd></dl>
<p>The <common field>s are also <automatic field>s, and initialized to each
corresponding <default> that is evaluated at the time the define-record-lambda
form is evaluated, and the values are shared with all the record lambdas that
are made by the constructors of the define-record-lambda form.</p>
<p>The other <automatic field>s except <virtual field>s are initialized to each
corresponding <default> that is evaluated at the time the record lambda is
made by a constructor. Each <default> of <virtual field>s is evaluated each
time when the field is accessed.</p>
<p>The <invisible field>s are externally nonexistent fields, that is, the fields
are invisible outside of the define-record-lambda form but accessible inside
of it. On the contrary, the <immutable field>s and <virtual field>s are
internally nonexistent fields, that is, the fields are visible outside of the
define-record-lambda form but inaccessible inside of it.</p>
<p>The <predicate> is a predicate procedure that returns #t for record lambdas
constructed by <constructor> or <constructor>s of a <group> and #f for
everything else.</p>
<pre>
Examples
;; invisible & immutable field example
(define-record-lambda stack
(`stack '()) ;invisible optional
(',push (lambda (s) (set! stack (cons s stack)))) ;immutable automatic
(,,pop (if (null? stack) ;virtual automatic
(error "null stack" stack)
(let ((s (car stack)))
(set! stack (cdr stack))
s))))
(define st (make-stack))
(st stack-stack) -> error stack-stack: undefined
(st stack-pop) -> error null stack ()
(st stack-push 2) -> error invisible or immutable field
((st stack-push) "rose")
((st stack-push) "lily")
((st stack-push) "sunflower")
(st stack-pop) -> "sunflower"
(st stack-pop) -> "lily"
(st stack-pop) -> "rose"
(st stack-pop) -> error null stack ()
(stack 'constructor) -> ((make-stack . make-stack-by-name)
(make-stack/s . make-stack-by-name/s))
(stack 'predicate) -> stack?
(stack 'field) -> ((total
(read-write-field ())
(read-only-field (push pop))
(invisible-field (stack)))
(types
(common-field ())
(required-field ())
(optional-field (stack))
(automatic-field (push pop))
(immutable-field (push))
(invisible-field (stack))
(virtual-field (pop))))
(stack 'index) -> ((stack-push . 0) (stack-pop . 1))
;; virtual field example
(let ()
(define-record-lambda circle
((radius) 1) ;read-write optional
(',area! (lambda (a) (set! radius (sqrt (/ a 3.14))))) ;immutable automatic
(,,area (* 3.14 radius radius))) ;virtual automatic
(list (let ((c (make-circle))) ;index
(list (c circle-area)
(c circle-radius)
(begin ((c circle-area!) (* 4 (c circle-area))) (c circle-area))
(c circle-radius)
(begin (c circle-radius 10) (c circle-area))
(c circle-radius)))
(let ((c (make-circle/s))) ;symbol
(list (c 'area)
(c 'radius)
(begin ((c 'area!) (* 4 (c 'area))) (c 'area))
(c 'radius)
(begin (c 'radius 10) (c 'area))
(c 'radius)))))
-> ((3.14 1 12.56 2.0 314.0 10) (3.14 1 12.56 2.0 314.0 10))
;; common field example
(let ()
(define-record-lambda record
(,@total-record 0) ;read-only automatic common
(,@total-connect 0) ;read-only automatic common
(,order-of-birth (begin ;read-only automatic
(set! total-record (+ 1 total-record))
total-record))
(,individual-connect 0) ;read-only automatic
(,,connect (begin ;virtual automatic
(set! individual-connect (+ 1 individual-connect))
(set! total-connect (+ 1 total-connect))
'connect)))
(let* ((record-1 (make-record/s))
(record-2 (make-record/s))
(record-3 (make-record/s))
(record-4 (make-record/s))
(record-5 (make-record/s)))
(record-1 'connect) (record-1 'connect) (record-1 'connect)
(record-1 'connect) (record-1 'connect) (record-2 'connect)
(record-2 'connect) (record-2 'connect) (record-2 'connect)
(record-3 'connect) (record-3 'connect) (record-3 'connect)
(record-4 'connect) (record-4 'connect) (record-5 'connect)
(map (lambda (o)
(list (list 'order-of-birth (o 'order-of-birth))
(list 'individual-connect (o 'individual-connect))
(list 'total-record (o 'total-record))
(list 'total-connect (o 'total-connect))))
(list record-1 record-2 record-3 record-4 record-5))))
->
(((order-of-birth 1) (individual-connect 5) (total-record 5) (total-connect 15))
((order-of-birth 2) (individual-connect 4) (total-record 5) (total-connect 15))
((order-of-birth 3) (individual-connect 3) (total-record 5) (total-connect 15))
((order-of-birth 4) (individual-connect 2) (total-record 5) (total-connect 15))
((order-of-birth 5) (individual-connect 1) (total-record 5) (total-connect 15)))
</pre>
<h1>Sample Implementation</h1>
<p>Sample implementations are provided based on both
<code>define-syntax</code> (syntax-rules with syntax-case or explicit
renaming macro) and <code>define-macro</code>. They're available both
in the <a href="https://github.com/scheme-requests-for-implementation/srfi-184">Github
repo</a> and in <a href= "https://srfi.schemers.org/srfi-184/srfi-184.tgz">this
<code>.tgz</code> file</a>.</p>
<h1>References</h1>
<table class="references">
<tr><td>[R6RS]</td><td>Michael Sperber, R. Kent Dybvig, Matthew Flatt, and Anton von Straaten: Revised(6) Report on the Algorithmic Language Scheme.<a class="eponymous" href="http://www.r6rs.org">http://www.r6rs.org</a></td></tr>
<tr><td>[SRFI 9]</td><td>Richard Kelsey: Defining Record Type.<a class="eponymous" href="https://srfi.schemers.org/srfi-9">http://srfi.schemers.org/srfi-9</a></td></tr>
<tr><td>[SRFI 100]</td><td>Joo ChurlSoo: Define-lambda-object.<a class="eponymous" href="https://srfi.schemers.org/srfi-100/">http://srfi.schemers.org/srfi-100/</a></td></tr></table>
<h1>Copyright</h1>
Copyright © Joo ChurlSoo (2012).
<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>
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>
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.
<hr>
<address>Editor: <a href="mailto:srfi-editors+at+srfi+dot+schemers+dot+org">Arthur A. Gleckler</a></address></body></html>