[To reply replace "Aaron.Sloman.XX" with "A.Sloman"]
Jonathan.Cunningham@tesco.net (Jonathan L Cunningham) wrote
an interesting message about closures and objectclass instances
> Date: Tue, 15 May 2001 11:01:28 GMT
>
....(lots cut out) ....
> But the bottom line is that an apparently "simple" mechanism --
> the pop closure -- is actually a very powerful abstraction,
> which hides a lot of behind-the-scenes complexity. And that
> is part of what makes it so useful.
Jonathan,
I liked your tutorial on closures and objectclass. I have temporarily
saved it in
http://www.cs.bham.ac.uk/~axs/misc/closures.and.classes.txt
to which I'll append this message.
One day I'll turn it into a TEACH file on closures and class instances.
If and when I get round to doing this, I'll let you have a chance to
edit it!
A few small points.
You wrote:
> There are some other ways in which the objectclass stuff
> looks ugly because of syntactic restrictions. For example,
> in C++ I could have used the same name "apply" for both
> the apply methods, instead of the clumsier "apply_two_arg"
> and "apply_three_arg".
This could be handled by using class_apply. From REF KEYS:
| class_apply(key) -> apply_p [procedure]
| apply_p -> class_apply(key)
| ....
| The updater of class_apply assigns the procedure apply_p to
| be the apply procedure for the class key key.
This means that instances can be treated as if they were procedures,
and when they are applied to arguments the class_apply procedure for
the Pop11 class to which they belong will be run.
Every pop11 entity has a class represented by its datakey
datakey("cat")=>
** <key word>
datakey(hd)=>
** <key procedure>
datakey(sqrt(-1))=>
** <key complex>
datakey(-1)=>
** <key integer>
which holds generic information about entities in that class,
including what should be done if you try to treat that entity
as a procedure, e.g. when applying a list to a number.
[cat dog mouse](2)=>
** dog
This is not to be confused with objectclass classes. See
HELP CLASSES
REF KEYS
REF OBJECTCLASS says that the method apply_instance is the default
class_apply for objeclass instances.
So you can redefine it as a method that does different things for
different classes. So with a little extra work (illustrated below) you
can then replace
> apply_two_arg(doublet, "chi", "omega");
with
doublet("chi", "omega");
So unlike c++ you will not even need to use "apply" to run your
objectclass-based closures!
> In Java, I needn't have declared
> the class "midclosure" -- I could have used an anonymous
> class. And so on.
I don't know how anonymous classes work in Java, but I guess there are
at least three reasons for using anonymous classes:
(a) privacy: the class and its methods can be accessed only in the
scope of the text where the class is introduced.
(b) efficiency because global identifiers don't need to be created
(c) syntactic convenience
In objectclass (a) and (b) can be achieved by using lvars or lconstant
in the class definition, and using lblock endlblock to restrict the
scope of the lexical identifiers. An example is given below.
Maybe (c), the extra syntactic convenience, could (if desired) be
achieved by defining new syntax words or macros to do the equivalent of
all this.
Anyhow here is an example illustrating the use of apply_instance,
lconstant and lblock, in connection with your example (slightly
simplified):
Suppose we have a procedure for which we wish to create a closure that
fixes the middle argument:
define apply_three(x, y, z);
[first ^x second ^y third ^z]=>
enddefine;
uses objectclass;
;;; start the lexical block
lblock
;;; define our new "anonymous" class
define :class lconstant midclosure;
slot middlearg;
enddefine;
;;; change the class_apply for its instances
define :method apply_instance(f:midclosure);
;;; get two arguments from the stack
lvars x, z;
-> (x, z);
apply_three(f, x, middlearg(f), z);
enddefine;
;;; create an instance inside the lexical block
define :instance doublet :midclosure;
middlearg = "psi";
enddefine;
endlblock;
;;; Then test that doublet works as expected, i.e. as a closure
;;; of apply_three
doublet("chi", "omega");
** [first chi second psi third omega]
doublet("cat", "dog");
** [first cat second psi third dog]
Q.E.D.
Compare this standard Pop-11 version which returns a closure of an
anonymous procedure which runs apply_three:
vars doublet2 =
procedure(y);
procedure(x, z);
apply_three(x, y, z)
endprocedure;
endprocedure("psi");
doublet2("cat", "dog");
** [first cat second psi third dog]
or, simplest of all, using partial application
vars doublet3 =
procedure(x, z, y);
apply_three(x, y, z)
endprocedure(% "psi" %);
doublet3("cat", "dog");
** [first cat second psi third dog]
Aaron
====
Aaron Sloman, ( http://www.cs.bham.ac.uk/~axs/ )
School of Computer Science, The University of Birmingham, B15 2TT, UK
EMAIL A.Sloman AT cs.bham.ac.uk (ReadATas@please !)
PAPERS: http://www.cs.bham.ac.uk/research/cogaff/
FREE TOOLS: http://www.cs.bham.ac.uk/research/poplog/freepoplog.html
|