HELP VIEWS A.Sloman Jan 1987
Revised: Adrian Howard Mar 1992
LIB VIEWS
LIB CURRENT_VIEW
Together these provide a general "structure-sharing" context mechanism
and specialised collections of procedures for operating on objects with
values in a context. The package may be used for a variety of
applications that need to manipulate histories or alternative possible
situations, including planning systems and "truth maintenance" systems.
The word "view" is used as a synonym for "context" in what follows.
See TEACH * VIEWS for an introduction and overview of the facilities
described below.
CONTENTS - (Use <ENTER> g to access sections)
-- Overview
-- General Facilities For Constructing And Accessing Views
-- Manipulating Views: Freeze, Merge, And Check Consistency
-- Facilities For Manipulating The "Current" View
-- A "Database" Of Items With Values In Views
-- Using LIB *VIEWS
-- Some Implementation Details
-- Notes
-- For More Information
-- Overview -----------------------------------------------------------
A context or view is an association between items and values. The same
item (or "key") may have different values in different views. A view may
have one or more parent views. If the object has no value in a
particular view, it may inherit a value from a parent or ancestor view.
This means that two views, can share some structure, making it
unnecessary to copy everything from an existing view to a new one. Only
the differences need to be recorded in the new one.
The general facilities provided operate on arbitrary networks of views.
These are provided by LIB * VIEWS.
There is a special subset of procedures for operating on the "current"
view and for "pushing" and "popping" views, e.g. in searching. These are
provided by LIB * CURRENT_VIEW
A still more specialised subset makes use of a pattern-directed database
of items mapped onto different values in different views, also in
LIB * CURRENT_VIEW
-- General Facilities For Constructing And Accessing Views ------------
Global constants:
no_view_value -> STRING
For items with no value in a given view. Doing
no_view_value -> view_value(view,item)
removes the item from view, so that it inherits from ancestors
of view, if any. -no_view_value- is a unique string
Global variables:
appquit -> BOOL
BOOL -> appquit
A boolean, default -false-, which if assigned -true- aborts the
search in -appview- or -mapview-. This can be used by a
procedure given to -appview- or -mapview-.
view_search -> WORD or P
WORD or P -> view_search
The value is "depth", "breadth" or procedure. This is used to
control -view_value-'s search up a view network for an ancestor
view with a value. For an example see TEACH * VIEWS/view_search
view_hash_default -> P
P -> view_hash_default
A procedure variable used by -newsubview-; default value is
-syshash-. User-assignable. Changing this does not alter
existing views.
view_hash_gc -> BOOL
BOOL -> view_hash_default
A boolean variable used by -newsubview- to decide whether
property tables should be re-hashed after garbage collection.
Default value is -false-. Changing it does not alter views
already created.
New data-type:
recordclass view view_map view_parents view_mark view_props;
This provides the following procedures: -view_map-,
-view_parents-, -view_mark-, -view_props-, -isview-, -consview-,
-destview-, -view_key- (see HELP *RECORDCLASS.)
Procedures:
view_map(VIEW) -> PROP
PROP -> view_map(VIEW)
The property associated with each view stores a mapping between
items and values for that view. This field should not be
changed. The property is created by -new_view-.
view_parents(VIEW) -> VIEW or LIST OF VIEWS
VIEW or LIST OF VIEWS -> view_parents(VIEW)
The parents field of a view contains the empty list -nil- if it
is the "root" view in a view network. Otherwise it contains the
parent view if there is only one, or a list of parents for
multiple inheritance.
If anything other than a view or (possibly empty) list of views
is stored as the view_parents of a view, then errors will
result.
view_mark(VIEW) -> INT FOR SYSTEM USE
This field is used by the mechanism that searches up a view
network to ensure that the same view is not examined twice. The
current mark is incremented at the beginning of each sweep. See
-new_view_mark-, below.
view_props(VIEW) -> ITEM
ITEM -> view_props(VIEW)
This field is for user programs, e.g. if it is necessary to keep
a list of those views which are descendants of a view they can
be stored here. Alternatively a property or other data-structure
associating information with a view can be stored in this field.
The default value is [].
new_view(LIST, SIZE, EXPAND, THRESH, HASH, EQTEST, GC,
PERM, PARENTS) -> VIEW
This is the most general view-constructor supplied. Apart from
the parent or list of parents, the arguments are 8 of the 9
arguments for *NEWANYPROPERTY (the missing one being the
"default value", which is determined by the constant:
-no_view_value-), and a list of parent nodes or a parent node.
The next procedure is a simplified version that will normally be
more useful.
newsubview(PARENTS, SIZE) -> VIEW
A specialised version of -new_view-, controlled by
-view_hash_default- and -view_hash_gc-. It uses "nonop =" for
equality testing. It a table of the size given, which will be
expanded when appropriate (see HELP * NEWANYPROPERTY.) Doing
newsubview(parents,size)
is equivalent to:
new_view(
[], size, 1, false,
view_hash_default, nonop =, view_hash_gc,
false, parents
)
view_value(VIEW, ITEM) -> VALUE
VALUE -> view_value(VIEW, ITEM)
Given a VIEW and an ITEM, this accesses or updates the VALUE of
that ITEM in that VIEW. If no VALUE is found then search for an
ancestor view with a value for the item. If no ancestor has a
value, then return -no_view_value-.
If the VALUE assigned is -no_view_value-, then remove the ITEM
from the VIEW.
new_view_mark() -> INT FOR SYSTEM USE
INT -> new_view_mark()
This procedure returns a unique integer, starting from the
largest possible negative integer that will fit into one 32 bit
machine word. Its updater gives it a new integer to start from.
It is used by -appview- to mark views as "seen" on each sweep
using the view_mark field.
appview(VIEW, PROCEDURE)
Using the search strategy determined by -view_search- apply the
procedure to every ancestor of view.
appviewmap(VIEW, PROCEDURE)
Using the search strategy determined by -view_search- apply
-appproperty- procedure to every ancestor of view and he
procedure.
-- Manipulating Views: Freeze, Merge, And Check Consistency -----------
If views are used for planning or "reason maintenance" or constructing
temporary hypothetical worlds which are later combined, then then
following procedures may be useful.
freeze_view(VIEW, LIST)
For each item in LIST find its current (possibly inherited value
in VIEW, and make it an actual value in VIEW. It then cannot be
affected by changes higher up the chain.
merge_view_values(VIEW1, VIEW2, CHECK_CLASH)
This copies the associations stored in VIEW1 into VIEW2.
CHECK_CLASH is either -false- or a procedure with the following
arguments:
check_clash(ITEM, VIEW1, VALUE1, VIEW2, VALUE2)
For every association that is stored explicitly in the
-view_map- of VIEW1, copy it into VIEW2. If CHECK_CLASH is
non-false, then for each item with a value in VIEW1 check that
there is not already a different value which is being
overwritten, and if there is invoke the procedure CHECK_CLASH
with arguments as above.
This can be used to combine a temporary hypothetical extension
of VIEW2 with VIEW2 after the extension has been tested and
found to be satisfactory.
view_consistent(LIST, VIEW1, VIEW2, EQPROC, REPORT)
This is used to test whether two views are consistent and if not
to report the inconsistency. LIST is a list of items that may
have values in the two views. If the value for an item in either
view is -no_view_value- then having a value in the other view
does not count as an inconsistency. Having two values which do
not satisfy the procedure EQPROC does count as an inconsistency,
in which case the following instruction is obeyed:
REPORT(ITEM, VIEW1, VAL1, VIEW2, VAL2)
where REPORT is a user supplied procedure.
-- Facilities For Manipulating The "Current" View ---------------------
Global variables:
current_view -> VIEW
VIEW -> current_view
The current view, or -false- if there is none.
current_viewname -> WORD
WORD -> current_viewname
The name of the current view --- produced by
gensym("view"). Its -valof- is current_view. It's
value is -false- if there is no current view.
view_stack -> LIST
LIST -> view_stack
A list of pairs, each pair containing a view and a name.
chatty -> BOOL
BOOL -> chatty
If -true- causes POP_VIEW and PUSH_VIEW to print out
information.
use_global_view -> BOOL
BOOL -> use_global_view
A boolean variable, default -true-. If -true- it optimises the
use of large collections of items given a value in an initial
view, with only a small proportion altered in descendent views.
global_view -> VIEW
VIEW -> global_view
The initial view, set up by -start_views-.
Procedures:
start_views(SIZE)
Initialises -current_view-, -current_viewname-, -view_stack- and
`gensym("view")' (see REF *gensym.) If
-use_global_view- is -true- it assigns the first -current_view-
to -global_view-. The argument determines the size of the
initial hash-table.
set_current_view(VIEW, WORD)
Assigns to -current_view- and -current_viewname- and pushes them
onto -view_stack-. Used by -push_view-.
push_view(SIZE)
Creates a new view and a new name (gensym("view")),
uses -set_current_view- to add them to -view_stack- and assign
them to -current_view- and -current_viewname-. The new name is
declared as a global variable. The argument determines the
hash_table size in the property used in the view.
pop_view()
Restores the previous -current_view- and -current_viewname-, and
removes the top element of -view_stack-.
current_view_value(ITEM) -> VALUE
VALUE -> current_view_value(ITEM)
This is equivalent to `view_value(current_view,ITEM)'.
-- A "Database" Of Items With Values In Views -------------------------
The facilities described below are partly analogous to the POP-11
database package (see HELP *DATABASE). The main difference is that that
package uses presence or absence of an item in the database to indicate
a truth value, whereas this one merely uses the database as a list of
items that have been assigned truth values in one or more views.
Global variables:
view_facts -> LIST
LIST -> view_facts
A list of lists which are mapped on to values in views.
it -> ITEM
ITEM -> it
The last element of -view_facts- examined or updated.
Procedures:
record_in_view(LIST, VALUE)
Ensure the LIST is in -view_facts- if necessary, and assign the
VALUE to it in -current_view-.
true_in_view(PATTERN) -> LIST or FALSE
If -view_facts- contains an item that matches the PATTERN and
has the value -true- in the current context, it is returned,
otherwise -false-. Since matching is done by -matches- (see HELP
*MATCHES) the values of pattern variables may be set.
false_in_view(PATTERN) -> BOOL
Equivalent to `not(true_in_view(PATTERN))'.
view_lookup(PATTERN)
This is like -true_in_view-, except that it returns no value,
and causes an error if no matching pattern with current value
-true- is found. It is useful mainly for retrieving parts of
stored items.
get_all_true(PATTERN) -> LIST
Returns a list of all the items in -view_facts- which are -true-
in -current_view- and match the pattern.
New loop syntax:
for_view <PATTERN>
with_value <EXPR> ;;; optional: defaults to -true-
in_view <VIEW> ;;; optional: defaults to -current_view-
in <LIST> ;;; optional: defaults to -view_facts-
do
<ACTION>
endfor_view
For every list in <LIST> that has value <EXPR> in <VIEW> and
which matches the <PATTERN>, the <ACTION> is executed, with the
variable "it" bound to the matching list. This is analogous to
the use of -foreach- (see HELP *FOREACH) with the POP-11
database. Variables in the PATTERN should be bound on each
iteration.
The optional components can occur in any order.
-- Using LIB *VIEWS ---------------------------------------------------
For an introduction to LIB VIEWS with examples see TEACH * VIEWS. This
includes a planning example.
For many applications the user will need to maintain a database of items
that have values associated with them relative to contexts. The list of
items stored in the global variable -view_facts-, with associated
procedures described above is a special case which may suffice for
relatively simple problems where the database is not large. In more
complex cases it will be necessary to provide an indexing scheme for
rapid pattern-directed access.
In such situations the user may wish to create "generator" procedures
which, when given an item specification, produces an repeater function
whose results can be scanned for items with a desired value in a desired
context. The looping construct -for_view-, described above and defined
in LIB * CURRENT_VIEW may provide some hints as to how to define a
convenient loop construct that iterates over a generator rather than a
list.
For some applications it will be necessary to associate with a view
other views that depend on it. The -view_props- field may be used for
this purpose. Alternatively, relationships between views like dependency
or justification may be represented in a separate network of
data-structures. A reason maintenance system would need to do this, for
example.
-- Some Implementation Details ----------------------------------------
Each view contains a list of "parent" views and a property table created
by -newanyproperty-. This requires the user to supply a hash function
and equality test, as explained in HELP *NEWANYPROPERTY. LIB *VIEWS uses
the system hash function -syshash- and the -class_hash- mechanism, see
HELP *SYSHASH for details.
The user may wish to provide an alternative hashing procedure and assign
it to -view_hash_default-.
There is a tradeoff between how effective a procedure is at
discriminating different structures and how fast it is. For example, a
very fast hashing procedure suitable for very small tables might be:
define global procedure hash_fast(item);
;;; Good for very small tables.
lvars item;
if issimple(item)
then item
else datasize(item)
endif
enddefine;
-- Notes --------------------------------------------------------------
1. To see in detail how the programs work, and how -newanyproperty- is
used see LIB * VIEWS
2. It is reasonably efficient because -newanyproperty- and -syshash- are
implemented in the core of POPLOG.
3. The easiest way to implement breadth first search up a view network
has a garbage collection overhead. This could be replaced by a more
complex program if people really want to make much use of breadth first
searching.
4. Active variables (access oriented programming), available from
Version 13, will make it feasible to have effects of changes in a
viewpoint automatically propagated, e.g. to a window display.
5. For applications where only trees, not networks, of views are
required, the program can be made somewhat simpler and more efficient.
Experienced users will find it easy to copy LIB *VIEWS and edit out the
portions concerned with searching up a network.
-- For More Information -----------------------------------------------
TEACH * VIEWS gives some detailed examples including an example of a
simple planner, and an example of a network in which some views have
more than one parent.
See HELP * PROPERTIES, * NEWPROPERTY, * NEWANYPROPERTY, * NEWMAPPING for
more information on properties.
HELP * SYSHASH describes the default value of -view_hash_default-.
HELP * DATABASE, TEACH * DATABASE, and HELP * MATCHES give more
information on the POPLOG database.
THIS PACKAGE IS LIKELY TO BE EXTENDED LATER
--- C.all/help/views
--- Copyright University of Sussex 1992. All rights reserved. ----------Author: A.Sloman Jan 1987