123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- @node Generic dispatch system
- @section Generic dispatch system
- @cindex multimethod dispatch
- @cindex type dispatch
- @cindex generic functions
- @cindex generic predicate dispatch
- @stindex methods
- @stindex meta-methods
- Scheme48 supports a CLOS-style generic procedure dispatch system, based
- on type predicates. The main interface is exported by @code{methods}.
- The internals of the system are exposed by the @code{meta-methods}
- structure, but they are not documented here. The generic dispatch
- system is used in Scheme48's @embedref{Writer, writer} and numeric
- system.
- @c @embedref{numeric system, Numeric system}.
- @dfn{Types} in Scheme48's generic dispatch system are represented using
- type predicates, rather than having every object have a single,
- well-defined `class.' The naming convention for simple types is to
- prefix the type name with a colon. The types support multiple
- inheritance. Method specificity is determined based on descending
- order of argument importance. That is, given two methods, @var{M} &
- @var{N}, such that they are both applicable to a given sequence of
- arguments, and an index @var{i} into that sequence, such that @var{i}
- is the first index in @var{M}'s & @var{N}'s lists of argument type
- specifiers, from left to right, where the type differs: if the type for
- @var{M}'s argument at @var{i} is more specific than the corresponding
- type in @var{N}'s specifiers, @var{M} is considered to be more specific
- than @var{N}, even if the remaining argument type specifiers in @var{N}
- are more specific.
- @deffn syntax define-simple-type name (supertype @dots{}) predicate
- Defines @var{name} to be a @dfn{simple type} with the given predicate
- and the given supertypes.
- @end deffn
- @deffn procedure singleton value @returns{} simple-type
- Creates a @dfn{singleton type} that matches only @var{value}.
- @end deffn
- @deffn syntax define-generic proc-name method-table-name [prototype]
- Defines @var{proc-name} to be a @dfn{generic procedure} that, when
- invoked, will dispatch on its arguments via the @dfn{method table} that
- @var{method-table-name} is defined to be and apply the most specific
- method it can determine defined in the @var{method-table-name} method
- table to its arguments. The convention for naming variables that will
- be bound to method tables is to add an ampersand to the front of the
- name. @var{Prototype} is a suggestion for what method prototypes
- should follow the shape of, but it is currently ignored.
- @end deffn
- @deffn syntax define-method method-table prototype body
- Adds a @dfn{method} to @var{method-table}, which is usually one defined
- by @code{define-generic}.@footnote{There is an internal interface, a
- sort of meta-object protocol, to the method dispatch system, but it is
- not yet documented.} @var{Prototype} should be a list whose elements
- may be either identifiers, in which case that parameter is not used for
- dispatching, or lists of two elements, the @code{car} of which is the
- parameter name and the @code{cadr} of which should evaluate to the type
- on which to dispatch. As in many generic dispatch systems of similar
- designs, methods may invoke the next-most-specific method. By default,
- the name @code{next-method} is bound in @var{body} to a nullary
- procedure that calls the next-most-specific method. The name of this
- procedure may be specified by the user by putting the sequence
- @code{"next" @var{next-method-name}} in @var{prototype}, in which case
- it will be @var{next-method-name} that is bound to that procedure. For
- example:
- @lisp
- (define-method &frob ((foo :bar) "next" frobozz)
- (if (mumble? foo)
- (frobozz) ; Invoke the next method.
- (yargh blargle foo)))@end lisp
- @end deffn
- A number of simple types are already defined & exported by the
- @code{methods} structure. Entries are listed as @code{@var{type-name}
- <- (@var{supertype} @dots{}), @var{predicate}}
- @itemize
- @item @code{:values <- (), (lambda (x) #t)} --- Abstract supertype of
- all run-time values
- @item @code{:value <- (:values), (lambda (x) #t)} --- Abstract
- supertype of all first-class values
- @item @code{:zero <- (:values), (lambda (x) #f)} --- Type that no
- objects satisfy
- @item @code{:number <- (:value), number?}
- @item @code{:complex <- (:number), complex?} --- (This happens to be
- equivalent to @code{:number}.)
- @item @code{:real <- (:complex), real?}
- @item @code{:rational <- (:real), rational?}
- @item @code{:integer <- (:rational), integer?}
- @item @code{:exact-integer <- (:integer),
- (lambda (x) (and (integer? x) (exact? x)))}
- @item @code{:boolean <- (:value), boolean?}
- @item @code{:symbol <- (:value), symbol?}
- @item @code{:char <- (:value), char?}
- @item @code{:null <- (:value), null?}
- @item @code{:pair <- (:value), pair?}
- @item @code{:vector <- (:value), vector?}
- @item @code{:string <- (:value), string?}
- @item @code{:procedure <- (:value), procedure?}
- @item @code{:input-port <- (:value), input-port?}
- @item @code{:output-port <- (:value), output-port?}
- @item @code{:eof-object <- (:value), eof-object?}
- @item @code{:record <- (:value), record?}
- @end itemize
|