by John Cowan (text), Arvydas Silanskas (implementation)
This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to
firstname.lastname@example.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
Compound objects are analogous to R6RS compound conditions, and are suitable for use in creating and handling conditions on non-R6RS systems, among other purposes. They encapsulate an immutable sequence of subobjects, which can be any object except another compound object. It is possible to implement R6RS compound conditions on top of compound objects, but not vice versa. Note that this SRFI does not provide any analogue to R6RS simple conditions, which are just records.
Compound objects serve as a kind of poor man's multiple inheritance without the usual complications of multiple inheritance. A compound object can be used to represent multiple otherwise unrelated aspects of a value or situation. Because they are sequences, they can be used to represent priorities of interpretation from higher to lower. Most of the operations described in this section treat a non-compound object identically to a compound object with the simple object as its sole component.
;; The following definitions are referenced in later examples (define-record-type <student> (student admission-year gpa) student? (admission-year admission-year) (gpa gpa)) ; grade-point average (define-record-type <teacher> (teacher hire-year salary) teacher? (hire-year hired) ; integer year (salary salary)) ; annualized (define alyssa (student 1986 4.0)) (define guy (teacher 1981 25000))
(make-compound obj ...
Create a compound object
containing the objects in obj... in the specified order.
If any object in obj... is itself a compound object,
it is flattened into its subobjects,
which are then added to the compound object in sequence.
;; These definitions are referenced in later examples (define george (make-compound 'teaching-assistant (student 1979 3.8) (teacher 1983 1000))) (define (teaching-assistant? obj) (eq? obj 'teaching-assistant))
#t if obj is a compound object, and
(compound? alyssa) => #f (compound? george) => #t
If obj is a compound object, returns a list of its subobjects;
otherwise, returns a list containing only obj.
(compound-subobjects alyssa) => (#<student>) (compound-subobjects george) => (teaching-assistant #<student> #<teacher>)
If obj is a compound object, returns the number of its subobjects as an exact integer. Otherwise, it returns 1.
(compound-length alyssa) => 1 (compound-length george) => 3
(compound-ref obj k
If obj is a compound object, returns the kth subobject.
Otherwise, obj is returned.
In either case, it is an error if k is less than
zero, or greater than or equal to
(compound-ref alyssa 0) => #<student> (compound-ref george 2) => #<teacher>
(compound-map mapper obj
If obj is a compound object, returns a compound object whose subobjects result from invoking mapper on each subobject of obj. Although the subobjects of the result are in the same order as the subobjects of obj, the order in which mapper is applied to them is unspecified. If any resulting subobject is itself a compound object, it is flattened into its subobjects, which are then added to the result in sequence.
If obj is not a compound object, returns a compound object whose only subobject is the result of applying mapper to obj.
(compound-map - (compound 1 2 3 4 5)) => #<compound: -1 -2 -3 -4 -5>
(compound-map->list mapper obj
If obj is a compound object, returns a list whose elements result from invoking mapper on each subobject of obj. Although the elements of the result are in the same order as the subobjects of obj, the order in which mapper is applied to them is unspecified.
If obj is not a compound object, returns a list whose only element is the result of applying mapper to obj.
(compound-map->list - (compound 1 2 3 4 5)) => (-1 -2 -3 -4 -5)
(compound-filter pred obj
Returns a compound object It contains the subobjects of obj that satisfy pred.
If obj is not a compound object, it returns a compound object. If obj satisfies pred, the only subobject of the result is obj. If obj does not satisfy pred, the result has no subobjects.
(compound-filter teacher? alyssa) => #<compound> (compound-filter teacher? george) => #<compound: #<teacher>>
(compound-predicate pred obj
If obj satisfies pred,
or is a compound object and
at least one of its subobjects satisfies pred,
#t; otherwise returns
(compound-predicate student? alyssa) => #t (compound-predicate student? george) => #t (compound-predicate teacher? george) => #t (compound-predicate teacher? guy) => #t (compound-predicate teaching-assistant? alyssa) => #f (compound-predicate teaching-assistant? guy) => #f (compound-predicate teaching-assistant? george) => #t
(compound-access predicate accessor default obj
If obj satisfies obj, accessor is applied to
obj and the result is returned.
Otherwise, if obj is a compound object, accessor is applied to
the first subobject that satisfies obj, and the result is returned.
Otherwise, default is returned.
(define (uni-member-hire-year obj) (compound-access teacher? hire-year #f obj)) (uni-member-hire-year alyssa) => #f (uni-member-hire-year guy) => 1981 (uni-member-hire-year george) => 1983 (uni-member-hire-year (make-compound '(27 42 98) 'fire!)) => #f
The sample implementation is available in the GitHub repository.
Thanks to the participants on the mailing list.
© 2021 John Cowan, Arvydas Silanskas.
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.