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
|
* Function Cells:: Accessing or setting the function definition
|
||||||
of a symbol.
|
of a symbol.
|
||||||
* Closures:: Functions that enclose a lexical environment.
|
* Closures:: Functions that enclose a lexical environment.
|
||||||
|
* OClosures:: Function objects with meta-data.
|
||||||
* Advising Functions:: Adding to the definition of a function.
|
* Advising Functions:: Adding to the definition of a function.
|
||||||
* Obsolete Functions:: Declaring functions obsolete.
|
* Obsolete Functions:: Declaring functions obsolete.
|
||||||
* Inline Functions:: Defining functions that the compiler
|
* Inline Functions:: Defining functions that the compiler
|
||||||
|
|
|
@ -22,7 +22,7 @@ define them.
|
||||||
* Function Cells:: Accessing or setting the function definition
|
* Function Cells:: Accessing or setting the function definition
|
||||||
of a symbol.
|
of a symbol.
|
||||||
* Closures:: Functions that enclose a lexical environment.
|
* 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.
|
* Advising Functions:: Adding to the definition of a function.
|
||||||
* Obsolete Functions:: Declaring functions obsolete.
|
* Obsolete Functions:: Declaring functions obsolete.
|
||||||
* Inline Functions:: Functions that the compiler will expand inline.
|
* Inline Functions:: Functions that the compiler will expand inline.
|
||||||
|
@ -1581,56 +1581,69 @@ examining or altering the structure of closure objects.
|
||||||
|
|
||||||
@node OClosures
|
@node OClosures
|
||||||
@section Open Closures
|
@section Open Closures
|
||||||
|
@cindex oclosures
|
||||||
|
@cindex open closures
|
||||||
|
|
||||||
Traditionally, functions are opaque objects which offer no other
|
Traditionally, functions are opaque objects which offer no other
|
||||||
functionality but to call them. Emacs Lisp functions aren't fully
|
functionality but to call them. (Emacs Lisp functions aren't fully
|
||||||
opaque since you can extract some info out of them such as their
|
opaque since you can extract some info out of them such as their
|
||||||
docstring, their arglist, or their interactive spec, but they are
|
docstring, their arglist, or their interactive spec, but they are
|
||||||
mostly opaque. This is usually what we want, but occasionally we need
|
still mostly opaque.) This is usually what we want, but occasionally
|
||||||
functions to expose a bit more information about themselves.
|
we need functions to expose a bit more information about themselves.
|
||||||
|
|
||||||
OClosures are functions which carry additional type information,
|
@dfn{Open closures}, or @dfn{OClosures} for short, are function
|
||||||
and expose some information in the form of slots which you can access
|
objects which carry additional type information and expose some
|
||||||
|
information about themselves in the form of slots which you can access
|
||||||
via accessor functions.
|
via accessor functions.
|
||||||
|
|
||||||
They are defined in two steps: first @code{oclosure-define} is used to
|
OClosures are defined in two steps: first you use
|
||||||
define new OClosure types by specifying the slots carried by those
|
@code{oclosure-define} to define a new OClosure type by specifying the
|
||||||
OClosures, and then @code{oclosure-lambda} is used to create an
|
slots carried by the OClosures of this type, and then you use
|
||||||
OClosure object of a given type.
|
@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
|
@example
|
||||||
(defun kbd-macro (key-sequence)
|
(defun kbd-macro (key-sequence)
|
||||||
(lambda (&optional arg)
|
(lambda (&optional arg)
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(execute-kbd-macro key-sequence arg)))
|
(execute-kbd-macro key-sequence arg)))
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
But with such a definition there is no easy way to extract the
|
But with such a definition there is no easy way to extract the
|
||||||
@var{key-sequence} from that function, for example to print it.
|
@var{key-sequence} from that function, for example to print it.
|
||||||
|
|
||||||
We can solve this problem using OClosures as follows. First we define
|
We can solve this problem using OClosures as follows. First we define
|
||||||
the type of our keyboard macros (to which we decided to add
|
the type of our keyboard macros (to which we decided to add
|
||||||
a @code{counter} slot while at it):
|
a @code{counter} slot while at it):
|
||||||
|
|
||||||
@example
|
@example
|
||||||
(oclosure-define kbd-macro
|
(oclosure-define kbd-macro
|
||||||
"Keyboard macro."
|
"Keyboard macro."
|
||||||
keys (counter :mutable t))
|
keys (counter :mutable t))
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
After which we can rewrite our @code{kbd-macro} function:
|
After which we can rewrite our @code{kbd-macro} function:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
(defun kbd-macro (key-sequence)
|
(defun kbd-macro (key-sequence)
|
||||||
(oclosure-lambda (kbd-macro (keys key-sequence) (counter 0))
|
(oclosure-lambda (kbd-macro (keys key-sequence) (counter 0))
|
||||||
(&optional arg)
|
(&optional arg)
|
||||||
(interactive "p")
|
(interactive "P")
|
||||||
(execute-kbd-macro keys arg)
|
(execute-kbd-macro keys arg)
|
||||||
(setq counter (1+ counter))))
|
(setq counter (1+ counter))))
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
As you can see, the @code{keys} and @code{counter} slots of the
|
As you can see, the @code{keys} and @code{counter} slots of the
|
||||||
OClosure can be accessed as local variables from within the body
|
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
|
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:
|
body of the OClosure, for example to describe a keyboard macro:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
(defun describe-kbd-macro (km)
|
(defun describe-kbd-macro (km)
|
||||||
(if (not (eq 'kbd-macro (oclosure-type 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)))
|
(counter (kbd-macro--counter km)))
|
||||||
(message "Keys=%S, called %d times" keys counter))))
|
(message "Keys=%S, called %d times" keys counter))))
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
Where @code{kbd-macro--keys} and @code{kbd-macro--counter} are
|
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
|
This macro defines a new OClosure type along with accessor functions
|
||||||
for its slots. @var{name} can be a symbol (the name of
|
for its @var{slots}. @var{oname} can be a symbol (the name of the new
|
||||||
the new type), or a list of the form @code{(@var{name} . @var{type-props})} in
|
type), or a list of the form
|
||||||
which case @var{type-props} is a list of additional properties.
|
@w{@code{(@var{oname} . @var{type-props})}}, in which case
|
||||||
@var{slots} is a list of slot descriptions where each slot can be
|
@var{type-props} is a list of additional properties of this oclosure
|
||||||
either a symbol (the name of the slot) or it can be of the form
|
type. @var{slots} is a list of slot descriptions where each slot can
|
||||||
@code{(@var{slot-name} . @var{slot-props})} where @var{slot-props} is
|
be either a symbol (the name of the slot) or it can be of the form
|
||||||
a property list.
|
@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
|
@table @code
|
||||||
@code{@var{name}--@var{slot-name}}. By default slots are immutable.
|
@item (:predicate @var{pred-name})
|
||||||
If you need a slot to be mutable, you need to specify it with the
|
This requests creation of a predicate function named @var{pred-name}.
|
||||||
@code{:mutable} slot property, after which it can be mutated for
|
This function will be used to recognize OClosures of the type
|
||||||
example with @code{setf}.
|
@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
|
For each slot in @var{slots}, the @code{oclosure-define} macro creates
|
||||||
functional update functions according to @var{type-props}:
|
an accessor function named @code{@var{oname}--@var{slot-name}}; these
|
||||||
a @code{(:predicate @var{pred-name})} in the @var{type-props} causes
|
can be used to access the values of the slots. The slot definitions
|
||||||
the definition of a predicate function under the name @var{pred-name},
|
in @var{slots} can specify the following properties of the slots:
|
||||||
and @code{(:copier @var{copier-name} @var{copier-arglist})} causes the
|
|
||||||
definition of a functional update function which takes an OClosure of
|
@table @code
|
||||||
type @var{name} as first argument and returns a copy of it with the
|
@item :mutable @var{val}
|
||||||
slots named in @var{copier-arglist} modified to the value passed in the
|
By default, slots are immutable, but if you specify the
|
||||||
corresponding argument.
|
@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
|
@end defmac
|
||||||
|
|
||||||
@defmac oclosure-lambda (type . slots) arglist &rest body
|
@defmac oclosure-lambda (type . slots) arglist &rest body
|
||||||
This macro creates an anonymous OClosure of type @var{type}.
|
This macro creates an anonymous OClosure of type @var{type}, which
|
||||||
@var{slots} should be a list of elements of the form @code{(@var{slot-name}
|
should have been defined with @code{oclosure-define}. @var{slots}
|
||||||
@var{exp})}.
|
should be a list of elements of the form
|
||||||
At run time, each @var{exp} is evaluated, in order, after which
|
@w{@code{(@var{slot-name} @var{expr})}}. At run time, each @var{expr}
|
||||||
the OClosure is created with its slots initialized with the
|
is evaluated, in order, after which the OClosure is created with its
|
||||||
resulting values.
|
slots initialized with the resulting values.
|
||||||
|
|
||||||
When called as a function, the OClosure will accept arguments
|
When called as a function (@pxref{Calling Functions}), the OClosure
|
||||||
according to @var{arglist} and will execute the code in @var{body}.
|
created by this macro will accept arguments according to @var{arglist}
|
||||||
@var{body} can refer to the value of any of its slot directly as if it
|
and will execute the code in @var{body}. @var{body} can refer to the
|
||||||
were a local variable that had been captured by static scoping.
|
value of any of its slot directly as if it were a local variable that
|
||||||
|
had been captured by static scoping.
|
||||||
@end defmac
|
@end defmac
|
||||||
|
|
||||||
@defun oclosure-type object
|
@defun oclosure-type object
|
||||||
This function returns the OClosure type (a symbol) of @var{object} if it is an
|
This function returns the OClosure type (a symbol) of @var{object} if
|
||||||
OClosure, and @code{nil} otherwise.
|
it is an OClosure, and @code{nil} otherwise.
|
||||||
@end defun
|
@end defun
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue