123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- @node Records
- @section Records
- @cindex abstract data types
- @cindex opaque data types
- Scheme48 provides several different levels of a record facility. Most
- programmers will probably not care about the two lower levels; the
- syntactic record type definers are sufficient for abstract data types.
- @cindex defining record types
- @cindex record types, defining
- @stindex define-record-types
- @stindex defrecord
- @stindex srfi-9
- At the highest level, there are two different record type definition
- macros. Richard Kelsey's is exported from the @code{defrecord}
- structure; Jonathan Rees's is exported from @code{define-record-types}.
- They both export a @code{define-record-type} macro and the same
- @code{define-record-discloser} procedure; however, the macros are
- dramatically different. Scheme48 also provides [SRFI 9], which is
- essentially Jonathan Rees's record type definition macro with a slight
- syntactic difference, in the @code{srfi-9} structure. Note, however,
- that @code{srfi-9} does not export @code{define-record-discloser}. The
- difference between Jonathan Rees's and Richard Kelsey's record type
- definition macros is merely syntactic convenience; Jonathan Rees's more
- conveniently allows for arbitrary naming of the generated variables,
- whereas Richard Kelsey's is more convenient if the naming scheme varies
- little.
- @subsection Jonathan Rees's @code{define-record-type} macro
- @deffn syntax define-record-type
- @lisp
- (define-record-type @var{record-type-name} @var{record-type-variable}
- (@var{constructor} @var{constructor-argument} @dots{})
- [@var{predicate}]
- (@var{field-tag} @var{field-accessor} [@var{field-modifier}])
- @dots{})@end lisp
- This defines @var{record-type-variable} to be a record type descriptor.
- @var{Constructor} is defined to be a procedure that accepts the listed
- field arguments and creates a record of the newly defined type with
- those fields initialized to the corresponding arguments.
- @var{Predicate}, if present, is defined to be the disjoint (as long as
- abstraction is not violated by the lower-level record interface) type
- predicate for the new record type. Each @var{field-accessor} is
- defined to be a unary procedure that accepts a record type and returns
- the value of the field named by the corresponding @var{field-tag}.
- Each @var{field-modifier}, if present, is defined to be a binary
- procedure that accepts a record of the new type and a value, which it
- assigns the field named by the corresponding @var{field-tag} to. Every
- @var{constructor-argument} must have a corresponding @var{field-tag},
- though @var{field-tag}s that are not used as arguments to the record
- type's constructor are simply uninitialized when created. They should
- have modifiers: otherwise they will never be initialized.
- It is worth noting that Jonathan Rees's @code{define-record-type} macro
- does not introduce identifiers that were not in the original macro's
- input form.
- For example:
- @lisp
- (define-record-type pare rtd/pare
- (kons a d)
- pare?
- (a kar)
- (d kdr set-kdr!))
- (kar (kons 5 3))
- @result{} 5
- (let ((p (kons 'a 'c)))
- (set-kdr! p 'b)
- (kdr p))
- @result{} b
- (pare? (kons 1 2))
- @result{} #t
- (pare? (cons 1 2))
- @result{} #f@end lisp
- @end deffn
- There is also a variant of Jonathan Rees's @code{define-record-type}
- macro for defining record types with fields whose accessors and
- modifiers respect @embedref{Optimistic concurrency, optimistic
- concurrency} by logging in the current proposal.
- @subsection Richard Kelsey's @code{define-record-type} macro
- @deffn syntax define-record-type
- @lisp
- (define-record-type @var{type-name}
- (@var{argument-field-specifier} @dots{})
- (@var{nonargument-field-specifier} @dots{}))
- @var{argument-field-specifier} @returns{}
- @var{field-tag} Immutable field
- | (@var{field-tag}) Mutable field
- @var{nonargument-field-specifier} @returns{}
- @var{field-tag} Uninitialized field
- | (@var{field-tag} @var{exp}) Initialized with @var{exp}'s value@end lisp
- @c Huh? ---> ^^^^^^ -- oh, due to extra @var{}
- This defines @code{type/@var{type-name}} to be a record type descriptor
- for the newly defined record type, @code{@var{type-name}-maker} to be
- a constructor for the new record type that accepts arguments for every
- field in the argument field specifier list, @code{@var{type-name}?} to
- be the disjoint type predicate for the new record type, accessors for
- each field tag @var{field-tag} by constructing an identifier
- @code{@var{type-name}-@var{field-tag}}, and modifiers for each argument
- field tag that was specified to be mutable as well as each nonargument
- field tag. The name of the modifier for a field tag @var{field-tag} is
- constructed to be
- @code{set-@var{type-name}-@var{field-tag}!}.
- Note that Richard Kelsey's @code{define-record-type} macro @emph{does}
- concatenate & introduce new identifiers, unlike Jonathan Rees's.
- For example, a use of Richard Kelsey's @code{define-record-type} macro
- @lisp
- (define-record-type pare
- (kar
- (kdr))
- (frob
- (mumble 5)))@end lisp
- @noindent
- is equivalent to the following use of Jonathan Rees's macro
- @lisp
- (define-record-type pare type/pare
- (%pare-maker kar kdr mumble)
- pare?
- (kar pare-kar)
- (kdr pare-kdr set-pare-kdr!)
- (frob pare-frob set-pare-frob!)
- (mumble pare-mumble set-pare-mumble!))
- (define (pare-maker kar kdr)
- (%pare-maker kar kdr 5))@end lisp
- @end deffn
- @subsection Record types
- @cindex programmatic record types
- @cindex record types, programmatic
- @stindex record-types
- Along with two general record type definition facilities, there are
- operations directly on the record type descriptors themselves, exported
- by the @code{record-types} structure. (Record type descriptors are
- actually records themselves.)
- @deffn procedure make-record-type name field-tags @returns{} record-type-descriptor
- @deffnx procedure record-type? object @returns{} boolean
- @code{Make-record-type} makes a record type descriptor with the given
- name and field tags. @code{Record-type?} is the disjoint type
- predicate for record types.
- @end deffn
- @deffn procedure record-type-name rtype-descriptor @returns{} symbol
- @deffnx procedure record-type-field-names rtype-descriptor @returns{} symbol-list
- Accessors for the two record type descriptor fields.
- @end deffn
- @deffn procedure record-constructor rtype-descriptor argument-field-tags @returns{} constructor-procedure
- @deffnx procedure record-predicate rtype-descriptor @returns{} predicate-procedure
- @deffnx procedure record-accessor rtype-descriptor field-tag @returns{} accessor-procedure
- @deffnx procedure record-modifier rtype-descriptor field-tag @returns{} modifier-procedure
- Constructors for the various procedures relating to record types.
- @code{Record-constructor} returns a procedure that accepts arguments
- for each field in @var{argument-field-tags} and constructs a record
- whose record type descriptor is @var{rtype-descriptor}, initialized
- with its arguments. @code{Record-predicate} returns a disjoint type
- predicate for records whose record type descriptor is
- @var{rtype-descriptor}. @code{Record-accessor} and
- @code{record-modifier} return accessors and modifiers for records
- whose record type descriptor is @var{rtype-descriptor} for the given
- fields.
- @end deffn
- @deffn procedure define-record-discloser rtype-descriptor discloser @returns{} unspecific
- Defines the method by which records of type @var{rtype-descriptor} are
- disclosed (@pxref{Writer}). This is also exported by
- @code{define-record-types} and @code{defrecord}.
- @end deffn
- @deffn procedure define-record-resumer rtype-descriptor resumer @returns{} unspecified
- Sets @var{rtype-descriptor}'s record resumer to be @var{resumer}. If
- @var{resumer} is @code{#t} (the default), records of this type require
- no particular reinitialization when found in @embedref{Suspending and
- resuming heap images, dumped heap images}; if @var{resumer} is
- @code{#f}, records of the type @var{rtype-descriptor} may not be
- dumped in heap images; finally, if it is a procedure, and the heap
- image is resumed with the @embedref{Suspending and resuming heap
- images, usual image resumer}, it is applied to each record whose
- record type descriptor is @var{rtype-descriptor} after the run-time
- system has been initialized and before the argument to
- @code{usual-resumer} is called.
- @end deffn
- @stindex records-internal
- The @code{records-internal} structure also exports these:
- @defvr {record type} :record-type
- The record type of record types.
- @end defvr
- @deffn procedure disclose-record record @returns{} disclosed
- This applies @var{record}'s record type descriptor's discloser procedure
- to @var{record} to acquire a disclosed representation; @pxref{Writer}.
- @end deffn
- For expository purposes, the record type record type might have been
- defined like so with Jonathan Rees's @code{define-record-type} macro:
- @lisp
- (define-record-type record-type :record-type
- (make-record-type name field-names)
- record-type?
- (name record-type-name)
- (field-names record-type-field-names))@end lisp
- @noindent
- or like so with Richard Kelsey's @code{define-record-type} macro:
- @lisp
- (define-record-type record-type
- (name field-names)
- ())@end lisp
- @noindent
- Of course, in reality, these definitions would have severe problems
- with circularity of definition.
- @subsection Low-level record manipulation
- @cindex records, low-level access to
- @cindex low-level access to records
- @stindex records
- Internally, records are represented very similarly to vectors, and as
- such have low-level operations on them similar to vectors, exported by
- the @code{records} structure. Records usually reserve the slot at
- index 0 for their record type descriptor.
- @strong{Warning:} The procedures described here can be very easily
- misused to horribly break abstractions. Use them very carefully, only
- in very limited & extreme circumstances!
- @deffn procedure make-record length init @returns{} record
- @deffnx procedure record elt @dots{} @returns{} record
- @deffnx procedure record? object @returns{} boolean
- @deffnx procedure record-length record @returns{} integer
- @deffnx procedure record-ref record index @returns{} value
- @deffnx procedure record-set! record index object @returns{} unspecified
- Exact analogues of similarly named vector operation procedures.
- @end deffn
- @deffn procedure record-type record @returns{} value
- This returns the record type descriptor of @var{record}, @ie{} the
- value of the slot at index 0 in @var{record}.
- @end deffn
|