Minor copyedits of documentation of OClosures
* doc/lispref/functions.texi (OClosures): Improve wording, indexing, and markup; add details.
This commit is contained in:
parent
3a651773d2
commit
119b3a4dba
2 changed files with 94 additions and 50 deletions
|
@ -569,6 +569,7 @@ Functions
|
|||
* Function Cells:: Accessing or setting the function definition
|
||||
of a symbol.
|
||||
* Closures:: Functions that enclose a lexical environment.
|
||||
* OClosures:: Function objects with meta-data.
|
||||
* Advising Functions:: Adding to the definition of a function.
|
||||
* Obsolete Functions:: Declaring functions obsolete.
|
||||
* Inline Functions:: Defining functions that the compiler
|
||||
|
|
|
@ -22,7 +22,7 @@ define them.
|
|||
* Function Cells:: Accessing or setting the function definition
|
||||
of a symbol.
|
||||
* Closures:: Functions that enclose a lexical environment.
|
||||
* OClosures:: Function objects
|
||||
* OClosures:: Function objects with meta-data.
|
||||
* Advising Functions:: Adding to the definition of a function.
|
||||
* Obsolete Functions:: Declaring functions obsolete.
|
||||
* Inline Functions:: Functions that the compiler will expand inline.
|
||||
|
@ -1581,56 +1581,69 @@ examining or altering the structure of closure objects.
|
|||
|
||||
@node OClosures
|
||||
@section Open Closures
|
||||
@cindex oclosures
|
||||
@cindex open closures
|
||||
|
||||
Traditionally, functions are opaque objects which offer no other
|
||||
functionality but to call them. Emacs Lisp functions aren't fully
|
||||
Traditionally, functions are opaque objects which offer no other
|
||||
functionality but to call them. (Emacs Lisp functions aren't fully
|
||||
opaque since you can extract some info out of them such as their
|
||||
docstring, their arglist, or their interactive spec, but they are
|
||||
mostly opaque. This is usually what we want, but occasionally we need
|
||||
functions to expose a bit more information about themselves.
|
||||
still mostly opaque.) This is usually what we want, but occasionally
|
||||
we need functions to expose a bit more information about themselves.
|
||||
|
||||
OClosures are functions which carry additional type information,
|
||||
and expose some information in the form of slots which you can access
|
||||
@dfn{Open closures}, or @dfn{OClosures} for short, are function
|
||||
objects which carry additional type information and expose some
|
||||
information about themselves in the form of slots which you can access
|
||||
via accessor functions.
|
||||
|
||||
They are defined in two steps: first @code{oclosure-define} is used to
|
||||
define new OClosure types by specifying the slots carried by those
|
||||
OClosures, and then @code{oclosure-lambda} is used to create an
|
||||
OClosure object of a given type.
|
||||
OClosures are defined in two steps: first you use
|
||||
@code{oclosure-define} to define a new OClosure type by specifying the
|
||||
slots carried by the OClosures of this type, and then you use
|
||||
@code{oclosure-lambda} to create an OClosure object of a given type.
|
||||
|
||||
Let's say we want to define keyboard macros, i.e.@: interactive
|
||||
functions which re-execute a sequence of key events (@pxref{Keyboard
|
||||
Macros}). You could do it with a plain function as follows:
|
||||
|
||||
Say we want to define keyboard macros, i.e. interactive functions
|
||||
which re-execute a sequence of key events. You could do it with
|
||||
a plain function as follows:
|
||||
@example
|
||||
(defun kbd-macro (key-sequence)
|
||||
(lambda (&optional arg)
|
||||
(interactive "P")
|
||||
(execute-kbd-macro key-sequence arg)))
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
But with such a definition there is no easy way to extract the
|
||||
@var{key-sequence} from that function, for example to print it.
|
||||
|
||||
We can solve this problem using OClosures as follows. First we define
|
||||
the type of our keyboard macros (to which we decided to add
|
||||
a @code{counter} slot while at it):
|
||||
|
||||
@example
|
||||
(oclosure-define kbd-macro
|
||||
"Keyboard macro."
|
||||
keys (counter :mutable t))
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
After which we can rewrite our @code{kbd-macro} function:
|
||||
|
||||
@example
|
||||
(defun kbd-macro (key-sequence)
|
||||
(oclosure-lambda (kbd-macro (keys key-sequence) (counter 0))
|
||||
(&optional arg)
|
||||
(interactive "p")
|
||||
(interactive "P")
|
||||
(execute-kbd-macro keys arg)
|
||||
(setq counter (1+ counter))))
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
As you can see, the @code{keys} and @code{counter} slots of the
|
||||
OClosure can be accessed as local variables from within the body
|
||||
of the OClosure. But we can now also access them from outside of the
|
||||
body of the OClosure, for example to describe a keyboard macro:
|
||||
|
||||
@example
|
||||
(defun describe-kbd-macro (km)
|
||||
(if (not (eq 'kbd-macro (oclosure-type km)))
|
||||
|
@ -1639,53 +1652,83 @@ body of the OClosure, for example to describe a keyboard macro:
|
|||
(counter (kbd-macro--counter km)))
|
||||
(message "Keys=%S, called %d times" keys counter))))
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
Where @code{kbd-macro--keys} and @code{kbd-macro--counter} are
|
||||
accessor functions generated by the @code{oclosure-define} macro.
|
||||
accessor functions generated by the @code{oclosure-define} macro for
|
||||
oclosures whose type is @code{kbd-macro}.
|
||||
|
||||
@defmac oclosure-define name &optional docstring &rest slots
|
||||
@defmac oclosure-define oname &optional docstring &rest slots
|
||||
This macro defines a new OClosure type along with accessor functions
|
||||
for its slots. @var{name} can be a symbol (the name of
|
||||
the new type), or a list of the form @code{(@var{name} . @var{type-props})} in
|
||||
which case @var{type-props} is a list of additional properties.
|
||||
@var{slots} is a list of slot descriptions where each slot can be
|
||||
either a symbol (the name of the slot) or it can be of the form
|
||||
@code{(@var{slot-name} . @var{slot-props})} where @var{slot-props} is
|
||||
a property list.
|
||||
for its @var{slots}. @var{oname} can be a symbol (the name of the new
|
||||
type), or a list of the form
|
||||
@w{@code{(@var{oname} . @var{type-props})}}, in which case
|
||||
@var{type-props} is a list of additional properties of this oclosure
|
||||
type. @var{slots} is a list of slot descriptions where each slot can
|
||||
be either a symbol (the name of the slot) or it can be of the form
|
||||
@w{@code{(@var{slot-name} . @var{slot-props})}}, where
|
||||
@var{slot-props} is a property list of the corresponding slot
|
||||
@var{slot-name}.
|
||||
The OClosure type's properties specified by @var{type-props} can
|
||||
include the following:
|
||||
|
||||
For each slot, the macro creates an accessor function named
|
||||
@code{@var{name}--@var{slot-name}}. By default slots are immutable.
|
||||
If you need a slot to be mutable, you need to specify it with the
|
||||
@code{:mutable} slot property, after which it can be mutated for
|
||||
example with @code{setf}.
|
||||
@table @code
|
||||
@item (:predicate @var{pred-name})
|
||||
This requests creation of a predicate function named @var{pred-name}.
|
||||
This function will be used to recognize OClosures of the type
|
||||
@var{oname}. If this type property is not specified,
|
||||
@code{oclosure-define} will generate a default name for the
|
||||
predicate.
|
||||
@item (:parent @var{otype})
|
||||
This makes type @var{otype} of OClosures be the parent of the type
|
||||
@var{oname}. The OClosures of type @var{oname} inherit the
|
||||
@var{slots} defined by their parent type.
|
||||
@c FIXME: Is the above description of :parent correct?
|
||||
@item (:copier @var{copier-name} @var{copier-args})
|
||||
This causes the definition of a functional update function, knows as
|
||||
the @dfn{copier}, which takes an OClosure of type @var{oname} as its
|
||||
first argument and returns a copy of it with the slots named in
|
||||
@var{copier-args} modified to contain the value passed in the
|
||||
corresponding argument in the actual call to @var{copier-name}.
|
||||
@end table
|
||||
|
||||
Beside slot accessors, the macro can create a predicate and
|
||||
functional update functions according to @var{type-props}:
|
||||
a @code{(:predicate @var{pred-name})} in the @var{type-props} causes
|
||||
the definition of a predicate function under the name @var{pred-name},
|
||||
and @code{(:copier @var{copier-name} @var{copier-arglist})} causes the
|
||||
definition of a functional update function which takes an OClosure of
|
||||
type @var{name} as first argument and returns a copy of it with the
|
||||
slots named in @var{copier-arglist} modified to the value passed in the
|
||||
corresponding argument.
|
||||
For each slot in @var{slots}, the @code{oclosure-define} macro creates
|
||||
an accessor function named @code{@var{oname}--@var{slot-name}}; these
|
||||
can be used to access the values of the slots. The slot definitions
|
||||
in @var{slots} can specify the following properties of the slots:
|
||||
|
||||
@table @code
|
||||
@item :mutable @var{val}
|
||||
By default, slots are immutable, but if you specify the
|
||||
@code{:mutable} property with a non-@code{nil} value, the slot can be
|
||||
mutated, for example with @code{setf} (@pxref{Setting Generalized
|
||||
Variables}).
|
||||
@c FIXME: Some rationale and meaning of immutable slot is probably in
|
||||
@c order here.
|
||||
@item :type @var{val-type}
|
||||
This specifies the type of the values expected to appear in the slot.
|
||||
@c FIXME: What will happen if the value is of a different type? error?
|
||||
@end table
|
||||
@end defmac
|
||||
|
||||
@defmac oclosure-lambda (type . slots) arglist &rest body
|
||||
This macro creates an anonymous OClosure of type @var{type}.
|
||||
@var{slots} should be a list of elements of the form @code{(@var{slot-name}
|
||||
@var{exp})}.
|
||||
At run time, each @var{exp} is evaluated, in order, after which
|
||||
the OClosure is created with its slots initialized with the
|
||||
resulting values.
|
||||
This macro creates an anonymous OClosure of type @var{type}, which
|
||||
should have been defined with @code{oclosure-define}. @var{slots}
|
||||
should be a list of elements of the form
|
||||
@w{@code{(@var{slot-name} @var{expr})}}. At run time, each @var{expr}
|
||||
is evaluated, in order, after which the OClosure is created with its
|
||||
slots initialized with the resulting values.
|
||||
|
||||
When called as a function, the OClosure will accept arguments
|
||||
according to @var{arglist} and will execute the code in @var{body}.
|
||||
@var{body} can refer to the value of any of its slot directly as if it
|
||||
were a local variable that had been captured by static scoping.
|
||||
When called as a function (@pxref{Calling Functions}), the OClosure
|
||||
created by this macro will accept arguments according to @var{arglist}
|
||||
and will execute the code in @var{body}. @var{body} can refer to the
|
||||
value of any of its slot directly as if it were a local variable that
|
||||
had been captured by static scoping.
|
||||
@end defmac
|
||||
|
||||
@defun oclosure-type object
|
||||
This function returns the OClosure type (a symbol) of @var{object} if it is an
|
||||
OClosure, and @code{nil} otherwise.
|
||||
This function returns the OClosure type (a symbol) of @var{object} if
|
||||
it is an OClosure, and @code{nil} otherwise.
|
||||
@end defun
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue