Generator Package
Edited by Teitelman on December 24, 1982 12:24 am
takes an enumerator, i.e. a procedure which accepts a procedural argument and applies the procedure to each of the elements in a particular set, e.g. the atoms in the world, the files in a directory, etc., and converts it into a generator, which is an object with retained state such that applying successive calls of Generate to the generator will yield the elements in the set. One application of generators would be in conjunction with the spelling corrector, e.g. to perform spelling correction of a module name. An example of how to create a generator is found at the end of this file.
Generator: CEDAR DEFINITIONS =
BEGIN
Types
Handle: TYPE = REF HandleRecord;
HandleRecord: TYPE = RECORD[
clientData: REF ANY,
private: REF HandlePrivateRecord];
HandlePrivateRecord: TYPE;
Procedures
CreateGenerator: PROC[enumerator: PROC[self: Handle], clientData: REF ANYNIL] RETURNS[generator: Handle];
creates a generator and forks a process which starts the enumerator. This process will be detached when the enumerator runs out or is terminated. The generator can then be reinitialized and restarted using ReStart, thereby avoiding reallocating the space for the generator. However, each such initialization and reuse will fork a new process.
ReStart: PROC [self: Handle];
first terminating the generator if it has not yet been terminated..
Generate: PROC [self: Handle] RETURNS [next: REF ANY];
returns next element in the set. Returns the generator itself if there are no more.
Terminate: PROC [self: Handle];
informs the enumerator to terminate by having the next call to Produce return TRUE.
Produce: PROC [self: Handle, next: REF ANY] RETURNS[done: BOOLEAN];
To be used inside of the enumerator to produce the next element. This is how the enumerator tells the generator what the next element is. If returns TRUE, then the enumerator should be terminated (by whatever conventions it employs).
END.
For example, Atom.MapAtoms is a procedure which maps through all of the atoms in the world applying a given procedure to each one. To create a generator which will upon successive calls to Generate produce all of the atoms in the world, we simply construct a procedure of type PROC [self: Handle] which calls MapAtoms with an appropriate procedureal argument, namely one that uses Produce to return successive atoms, and terminates the MapAtoms if the call to Produce returns TRUE:
AtomEnumerator: PROC [self: Handle] = {
proc: PROC [atom: ATOM] = {IF Produce[self, atom] THEN ERROR Done}; -- the procedural argument to be given to MapAtoms.
Done: ERROR = CODE;
Atom.MapAtoms[proc ! Done => CONTINUE];
};
Then we simply call CreateGenerator on this enumeratr::
gen: Handle ← CreateGenerator[Enumerator];
Calling Generate[gen] will return successive atoms. Terminate[gen] will stop the enumerator.