make-rec...scriptor(3scm)
๐ make-record-constructor-descriptor, record-constructor โ procedural record construction ๐
hey bestie, welcome to the Scheme Programmer's Manual (yes, that's the manual name, don't @ me) โ this page is all about make-record-constructor-descriptor and record-constructor, and lowkey it's a whole journey. Buckle up. ๐ฆ
๐ธ LIBRARY ๐ธ
(import (rnrs)) ;R6RS
(import (rnrs records procedural)) ;R6RS
both of those, okay? not one, both. ๐
โจ SYNOPSIS โจ
(make-record-constructor-descriptor rtd parent-rcd protocol)
(record-constructor rcd)
๐ DESCRIPTION ๐
So make-record-constructor-descriptor returns a record-constructor descriptor (an rcd, for short) that specifies a record constructor (the constructor, for short). That constructor? It's the thing you use to construct record values of the type specified by rtd, and you get your hands on it via record-constructor. periodt. ๐
๐ง Record type descriptors ๐ง
The rtd argument must be a record-type descriptor created by make-record-type-descriptor(3scm). no substitutes, no vibes-based arguments, the real thing only. โจ
๐ฅ Protocols and base record types ๐ฅ
The protocol argument must be a procedure or #f. If it's #f, a default protocol procedure is supplied (more on that below, keep reading bestie). If protocol is a procedure, it gets handled analogously to the protocol expression in a define-record-type(7scm) form.
If rtd is a base record type, then parent-rcd must be #f. In that case, protocol is called by record-constructor with a single argument p, which is a procedure that expects one argument for every field of rtd and returns a record with the fields of rtd initialized to these arguments.
The procedure returned by protocol should call p once with the number of arguments p expects, and return the resulting record, like this:
(lambda (p)
(lambda (v1 v2 v3)
(p v1 v2 v3)))
Here, the call to p returns a record whose fields are initialized with the values of v1, v2, and v3. And fun fact โ the expression above is equivalent to (lambda (p) p). iconic. ๐
Note that the procedure returned by protocol is otherwise unconstrained; specifically, it can take any number of arguments.
๐ฆ Single inheritance of record types ๐ฆ
A constructor descriptor can also be used to create other constructor descriptors for subtypes of its own record type, by passing it as parent-rcd. generational talent tbh. ๐
If rtd is an extension of another record type parent-rtd and protocol is a procedure, parent-rcd must be a constructor descriptor of parent-rtd or #f.
If parent-rcd is a constructor descriptor, protocol is called by record-constructor with a single argument n, which is a procedure that accepts the same number of arguments as the constructor of parent-rcd and returns a procedure p that, when called, constructs the record itself. The p procedure expects one argument for every field of rtd (not including parent fields) and returns a record with the fields of rtd initialized to these arguments, and the fields of parent-rtd and its parents initialized as specified by parent-rcd.
The procedure returned by protocol should call n once with the number of arguments n expects, call the procedure p it returns once with the number of arguments p expects, and return the resulting record. A simple protocol in this case might be written as follows:
(lambda (n)
(lambda (v1 v2 v3 x1 x2 x3 x4)
(let ((p (n v1 v2 v3)))
(p x1 x2 x3 x4))))
This passes arguments v1, v2, v3 to n for parent-rcd and calls p with x1, x2, x3, x4 to initialize the fields of rtd itself. ๐
So basically โ the constructor descriptors for a record type form a sequence of protocols parallel to the sequence of record-type parents. Each constructor descriptor in the chain determines the field values for the associated record type. Child record constructors don't need to know the number or contents of parent fields, only the number of arguments accepted by the parent constructor. no cap, that's the whole design. ๐โจ
๐ The default protocol ๐
Protocol may be #f, specifying a default constructor that accepts one argument for each field of rtd (including the fields of its parent type, if any).
Specifically: if rtd is a base type, the default protocol procedure behaves as if it were (lambda (p) p).
If rtd is an extension of another type, then parent-rcd must be either #f or itself specify a default constructor, and the default protocol procedure behaves as if it were:
(lambda (n)
(lambda (v1 ... vj x1 ... xk)
(let ((p (n v1 ... vj)))
(p x1 ... xk))))
The resulting constructor accepts one argument for each of the record type's complete set of fields (including those of the parent record type, the parent's parent record type, etc.) and returns a record with the fields initialized to those arguments, with the field values for the parent coming before those of the extension in the argument list.
In the example, j is the complete number of fields of the parent type, and k is the number of fields of rtd itself. math girlies rise. ๐งฎ๐
โญ The default parent rcd โญ
If rtd is an extension of another record type and parent-rcd is #f, parent-rcd is treated as if it were a constructor descriptor for the parent rtd of rtd with a default protocol.
๐ Using record constructor descriptors ๐
The record-constructor procedure calls the protocol of rcd and returns the resulting constructor for records of the rcd. The constructor is a procedure that takes as many arguments as are required by the protocol. slay. ๐
๐ซถ IMPLEMENTATION NOTES ๐ซถ
Implementation responsibilities: if protocol is a procedure, the implementation must check the restrictions on it to the extent performed by applying it as described when the constructor is called. An implementation may check whether protocol is an appropriate argument before applying it.
so like โ checking is required, but checking early is optional. don't come for me, that's literally what it says. ๐
๐ RETURN VALUES ๐
make-record-constructor-descriptorโ returns a single value; a record constructor descriptor.record-constructorโ returns a single value; a procedure.
one value each, no greedy multi-value nonsense. ๐
๐ง EXAMPLES ๐ง
; This is a rather complex example from R6RS which
; demonstrates inheritance and protocols. A simpler
; example can be found in make-record-type-descriptor(3scm).
(define rtd1
(make-record-type-descriptor
'rtd1 #f #f #f #f
'#((immutable x1) (immutable x2))))
(define rtd2
(make-record-type-descriptor
'rtd2 rtd1 #f #f #f
'#((immutable x3) (immutable x4))))
(define rtd3
(make-record-type-descriptor
'rtd3 rtd2 #f #f #f
'#((immutable x5) (immutable x6))))
(define protocol1
(lambda (p)
(lambda (a b c)
(p (+ a b) (+ b c)))))
(define protocol2
(lambda (n)
(lambda (a b c d e f)
(let ((p (n a b c)))
(p (+ d e) (+ e f))))))
(define protocol3
(lambda (n)
(lambda (a b c d e f g h i)
(let ((p (n a b c d e f)))
(p (+ g h) (+ h i))))))
(define cd1
(make-record-constructor-descriptor
rtd1 #f protocol1))
(define cd2
(make-record-constructor-descriptor
rtd2 cd1 protocol2))
(define cd3
(make-record-constructor-descriptor
rtd3 cd2 protocol3))
(define make-rtd1 (record-constructor cd1))
(define make-rtd2 (record-constructor cd2))
(define make-rtd3 (record-constructor cd3))
(make-rtd3 1 2 3 4 5 6 7 8 9)
=> #[rtd3 x1: 3 x2: 5 x3: 9 x4: 11 x5: 15 x6: 17]
the way this example eats and leaves no crumbs ๐ญ๐ฅ three record types, three protocols, one beautiful chain. study it. ๐
๐ธ APPLICATION USAGE ๐ธ
See make-record-type-descriptor(3scm).
(that's it. that's the section. go read the other page bestie.) ๐ฆ
โจ COMPATIBILITY โจ
This procedure is unique to the R6RS record system. An equivalent procedure can be found in SRFI-237.
๐ ERRORS ๐
This procedure can raise exceptions with the following condition types:
&assertion(R6RS) โ The wrong number of arguments was passed or an argument was outside its domain. In particular,rtdmust be a record-type descriptor,parent-rcdmust be#for an appropriate record-constructor descriptor as described above. Theprotocolargument should be#for a procedure. However, see IMPLEMENTATION NOTES.
yeah that last bit matters โ go back up and read the implementation notes, i'm serious. ๐
๐ SEE ALSO ๐
make-record-type-descriptor(3scm), define-record-type(7scm)
โญ STANDARDS โญ
R6RS
๐ฆ HISTORY ๐ฆ
This procedure first appeared in R6RS as part of the record system. an icon from day one, honestly. ๐
๐ AUTHORS ๐
This page is part of the scheme-manpages project. It includes materials from the RnRS documents. More information can be found at https://github.com/schemedoc/manpages/.
shoutout to the maintainers, fr fr ๐ซถ
๐ BUGS ๐
There is no record-constructor-descriptor? predicate in R6RS.
not me finding out there's no predicate for this ๐ญ like hello?? anyway. now you know. ๐ธ
<div align="center">โจ๐๐๐๐ ๐ฆ๐ธ๐๐ง๐โญ๐๐ฅ๐ซถ๐๐โจ</div>
and that's the page bestie!! this whole thing is the Scheme Programmer's Manual version dated 2023-08-03, filed under make-rec...scriptor(3scm) (yes the title got truncated, we don't talk about it ๐). go forth and construct records. slay. ๐
โจ๐
๐ฆ where this page comes from
- nixpkgs unstable: scheme-manpages 0-unstable-2024-02-11
- ๐ the page's license: MIT
- Copyright (c) 2023 Gwen Weinholt
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms