Page Numbers: Yes First Page: 1
Heading:
April 28, 1979 12:39 PM[IVY]krl>document>match-seek-old
---from 2matchspecs---
2.1 LISP forms for invoking basic description operations
So far, we have given a general picture of how the interpreter works, and an abstract description of the basic processes for finding, comparing, and modifying descriptions. In each case, we have listed the "central arguments" and explained how they are used, while pushing a whole bunch of other issues into the background. These other aspects must be dealt with in order to specify a real useable set of functions which integrate with INTERLISP control structure. There are several dimensions which are common to all of the functions, and these are discussed first:
* The basic CLISP form
* Process descriptions
* Specifying a context
The form of expressions for basic description operations
In KRL-0, there were LISP functions for Match, Seek, Describe, etc. Their arguments consisted of one or two fixed inputs (corresponding to the central arguments described for each process in section 1.2) and a signal table. The signal table had to handle all the other parameters concerning how they did their job and what kind of outputs they returned. The result was the expectable Turing tar-pit, in which the theoretical possibilities were unlimited, and the actual programs tended to stick to a tiny cluster of cases which made only trivial use of the flexibility.
In KRL-1 there is a much higher demand on the practical useability of these functions, since they are the only user-available means of accessing the description structures themselves. The programmer cannot resort to a concoction of (FindFiller(GetPerspective(GetDescriptors(FindSlot.....)))), but must be able to do all of the necessary work using the KRL-1 functions for the processes of finding, comparing and modifying data structures.
KRL-1 attempts to provide mechanisms which are easier to specify and control than the notion of signal table. The signal table (or its current equivalent -- see the section on discrimination nets) is still necessary to handle special cases and errors, but it is not the basic means of paramaterization. Instead we have analyzed the most important parameters of the different processes, and provided structured ways of specifying them. The majority of useful combinations can be specified directly in the syntactic form.
The basic problem which had to be faced in designing the syntax was the large number of variations allowed in what is to be specified. There are many different potential parameters, and in any one call only a few need be given. The rest either have default values, or are irrelevant because of choices made in the others.
This situation is closely analagous to the problem of specifying looping control structures in a language like LISP. There are a wide variety of means for producing the successive values of the iteration variable, such as stepping through a list (either tails or CARs); counting from some number to another (perhaps with an increment other than 1); pulsing a generator; calling a next-value function with the previous value as its argument; etc., etc. There are equally many ways to decide when to stop, and still more ways to decide what to return (the last value found, a list of results, a concatenation of results, etc.). In INTERLISP this problem has been dealt with by having an extremely general iterative statement based on labelled optional order-independent arguments, and a complex compiler which produces a piece of standard LISP code based on the iterative statement.
KRL-1 has adopted this style for the specification of basic processes. There is no LISP function named Match. Instead, Match is defined as a CLISP word (using mechanisms standardly available in INTERLISP), and there is a compiler which converts any form whose initial word is Match into a piece of LISP code expressing the computation. This code is invisible to the user, just as the translation of an iterative statement is invisible to the user. This compiler is integrated with the data structure compiler (see section?? <the compiling paper>), and in many of the standard cases produces highly efficient code in the form a a series of record accesses. Section 3.?3.??? discusses the nature of the code produced by the KRL-1 statement compiler.
The general form for a KRL-1 process statement (as it appears in LISP code) is:
(procedureName mainArg key1 arg1 key2 arg2.....)
For each procedure name (e.g. Match, Seek, Augment...) one of the central arguments is designated as the main argument, and follows the initial word. Other possible arguments are associated with key words (like the until, collect, etc. of the iterative statement) and can be included in any order, or omitted. Table ??? shows all of the allowable procedure names and keys. They will be explained one by one in the following sections which try to give an intuitive feel for the dimensions along which each parameter affects the reasoning process.
The compiler will take default values for omitted arguments, and will signal an error if there is insufficient information to carry out the process. The key names must appear explicitly in the form (i.e. they are not evaluated). All of the other arguments are assumed to be LISP variables or expressions, whose value is a KRL description (see discussion below on integrating LISP values into KRL expressions).
The decision to have all arguments be descriptions (rather than specially interpreted atoms, canned expressions, etc. as in KRL-0) makes the syntax more uniform, and leaves everything semantically extensible. This can be done without unacceptable loss of efficiency because of the ability to compile description manipulating expressions).
Theoretically, one could imagine specifying arbitrarily complex descriptions for any of the parameters. This flexibility exists, but we are directly implementing what appear to be the most useful cases. The compiler is written with these cases in mind, and is able to do far more towards producing efficient code for them, than for more general descriptions. For most parameters (see section ???) there is a set of pre-planned canned descriptions to be used. Specifying anything other than one of these will result in the interpreter falling back on user provided routines for handling the details (similar to the current user-responsibility for handling all of the possible signals in a signal table). We envision gradually expanding the library of useful parameter descriptions, and also providing better frameworks for users to write their own.
Process descriptions
In addition to specifying the inputs and the output form in a basic process statement, we need to be able to directly constrain and influence the course of the process which will be carried out. There are two major areas of specification:
* Limitations on inference and access
* Scheduling and resource information
These will be specified by the keywords allowing and scheduling respectively. Thus, we might see a call:
(Seek \The biter from a Bite with bitten = Sally/
returning \A PrimaryDescription/
allowing \A FullSearch with actionTable = !StandardTable37/
scheduling \A ScheduledProcess with resources = 20/)
Some of the syntax has not yet been explained. Sections ??? <krlsyntax.bravo> and ??? <defining the meaning of the different descriptor types> go into much more detail. For the moment, the following two facts are sufficient:
Within a character string intended for the LISP reader, the pair backslash/slash (\....../) delimits a section to be read by the KRL reader. The corresponding description appears in the LISP structure when it is done.
Within a KRL structure, the prefix character bang (!) indicates that the following single atom or S-expression is in LISP syntax. Its meaning is that the object being described is the value of the LISP expression at use time (not initial read time). For specifying a description to be added or sought, the sequence @! is used, for reasons which are semantically important, but are best understood later.
Limiting inference and access
The ability to limit the number and type of inference and access steps is the key to making the basic description process general enough to handle everything from the details of data structure access to finding complex chains of reasoning through heuristc search. The same form of statement (e.g. Seek a primary description for the object described as....) takes on a completely different light in: a) the case where the only information which can be used is that appearing directly in the units named in the initial description, with no inferences being made; b) a case in which the entire knowledge base is to be searched and paths of inference attempted which could lead to finding the desired description.
The current set of canned descriptions for specifying the kinds of inference and access to be done are:
An ImmediateAccess
The only information to be used is that which appears explicitly in the description forms given as arguments. No further activations or inferences are to be made.
A CoreferenceAccess
Chains of coreference descriptors can be followed to access further information. If we have for example,
# Bite17
self: A Bite with biter = Fido
then a Seek given an initial description of The biter from Bite17 viewedAs a Bite will not be able to find the necessary information as an ImmediateAccess, since it needs to activate the self description from the unit Bite17. However, except for following coreferences, no other activations or inferences are done.
A CategoryAccess
Chains of prototypes will be followed to look for category conflicts. Otherwise, no accessing or inferences. This is a standard case for possible match.
All of the above three forms can be compiled directly into the equivalent of operations on LISP records, and therefore do not need to call any other basic processes recursively. Any other process which results in recursive calls to basic processes will eventually "bottom out" on these. In the case where the relevant units are declared for compilation, the code should be quite efficient.
Note that the bottoming out does not occur because the domain must bottom out, but will usually be one meta-level away. If the original search was for something meeting a description of A Dog..., the bottom level calls will be searches for A Perspective with prototype = Dog....
A FullSearch with actionTable = ...
This is the escape hatch for doing the full-fledged search of the problem space defined by accessing and inferences. It is clear that we need to build up more specialized versions of this (perhaps by giving it slots for things like "inferencesAllowed", "maximumDepth", etc. etc. in heuristic search tradition), but for the moment we have one general-purpose argument in the action discrimination net (see section ???) -- the equivalent of the KRL-0 signal path.
Scheduling and Resources
KRL-0 provided a general resource and scheduling mechanism which was used for anumber of purposes. However, its features were not generally used in controlling the Match and Seek processes because of the difficulty of using signal tables to specify process details. In KRL-1 there is a more general facility for supporting multiple agendas each with its own scheduler (see section ???). The pre-planned descriptions for running a process are:
A SimpleProcess (this is the default when nothing is specified)
The entire process will be run to completion before returning control to the function which called it.
Note: this isn’t quite true, since if the result is specified as being a generator, it will run to produce successive items. It might better be state "It will run until it is ready to produce a result".
A ScheduledProcess with ...
This is based on the unit (shown only partially here):
# ScheduledProcess
self: A Process
agenda: An Agenda
reasources: An Integer
The agenda can either be newly created for this particular call, or can be shared with other calls. It is a actor-like object which knows how to interpret various commands. The specified agenda is ued not only for the main processing, but also for the demons and servants invoked in its course. The details will not be described in this section, but will be fully explained in the section on control (section ??).
Shared contexts
In describing the basic search through the space of possible inferences and activations, we use the concept of an active context of descriptions which have been activated. In Section 1.3 we discussed the data structures which make it up, and the usefulness of sharing it between processes. In the simplest case, a fresh context is created for each call to a basic process, initially containing only the descriptions which were given as central arguments. In order to share contexts, it is necessary both to create a shared context, and to pass it on. The context can be specified (using the key word within) by giving any description which describes a context (for the detailed units see section ???). The system will seek a primary description which is coreferential with it, and will signal an error if none can be found. The LISP function NewContext produces a description which is a primary description of an otherwise unidentified unique context. If given a unit name as argument, that unit’s self description is used. The default is equivalent to:
... within !(NewContext) ...
For sharing, a new context is created, assigned to a LISP variable, and then any process which is to use it contains:
... within !variableName ...
Result descriptions for Seek
In specifying a Seek, the main argument is the initial description of the entity for which further information is being sought. If that entity is not a composite entity (set or sequence), then there are four different pre-planned specifications for what is to be sought: A PrimaryDescription, A Coreference, and A Pointer. As usual, anyting is allowed, but descriptions other than these will take a good deal of care to define and use.
In the first two cases, the value passed back when the expression is evaluated will be a genuine KRL description (or NIL, if nothing was found). In the first case, it will be the primary description for the entity referred to by the initial description. In the second, it will be a unit or slot coreference descriptor, where the slot pointed to (self slot in the case of a unit) is the primary description. <we need a way to specify whether that primary description is labelled as identifiable (See Section ??? for a discussion of identifiability)>. If the initial description turns out to refer to a LISP entity, and a Coreference is specified, a LISP descriptor form (the one specified in the syntax with a single quote) will be returned. If it refers to a string or number, the appropriate internal descriptor form will be returned.
The Pointer case will return one of the following (if it can find it):
* A LISP number, string, atom, or expression, if the referent is found to be one of those
* A pointer to a unit whose self slot contains the primary description for the sought-after entity (Note that this pointer is different from a unit coreference descriptor)
* A pointer to a compiled record, if the primary description for the entity consists of a single compiled record (this will be the case for all of the internal KRL objects)
Not every primary description can be converted to a pointer. In particular, this is not possible for primary descriptions which are in slots other than self. <should this be changed by adding another kind of pointer???????>. If the desired result is specified as a description (either PrimaryDescription or Coreference ), and the entity is itself a LISP object or internal KRL object, the appropriate description form will be created and returned.
If the sought-after entity is a set or sequence, then there is a set of further choices. If one of the above three result specifiers is used, the appropriate description or pointer for the composite entity as a whole will be returned if it can be found (e.g. a pointer to a unit whose self description is A Set with.....). In addition, there are composite forms based on the functionals: SetEnumerationOf, SequenceEnumerationOf, ListOf, and GeneratorOf.
Each of these takes a single argument which is one of the possible specifiers for non-composite entities. Thus, assuming that the unit Problem has a slot named columns which contains a sequence of descriptions of columns (in a cryptarithmetic problem), we might have any of:
(Seek \The columns from !ThisProblem viewedAs a Problem/
returning \SequenceEnumerationOf(A Coreference)/)
(Seek \The columns from !ThisProblem viewedAs a Problem/
returning \ListOf(A Pointer)/)
(Seek \The columns from !ThisProblem viewedAs a Problem/
returning \GeneratorOf(A PrimaryDescription)/)
In the first case, a single description would be returned. It would look something like: <Column1, Column2, Column3, Column4>. In the second case, the value returned would be a LISP list, containing four unit pointers (not unit coreference descriptors). If printed, it would look like: (\Column1 \Column2 \Column3 \Column4) since unit pointers are printed by the LISP printer preceded by a backslash. The third case would return a generator handle. It would usually be used in one of the canned generator forms (see the INTERLISP manual, December 1975 version, pp...??), for example:
(for nextDesc
outOf (Seek \The columns from !ThisProblem viewedAs a Problem/
returning \GeneratorOf(A PrimaryDescription)/
allowing \A CoreferenceAccess/)
when (Match nextDesc
descriptive \A Column with age = GreaterThan(10)/
allowing \An ImmediateAccess/)
do (Describe nextDesc \An OldWornOutColumn/))
The generator makes it possible to start doing the operations on the elements found by Seek without waiting for them all to be found. If they are all expected to be found at once, then it is equally good (and probably more efficient) to use the ListOf form and the normal iterative statement in. Note that of the four forms, all but the generator form will wait until it can be demonstrated that the enumeration includes all members of the set or sequence before returning anything.
---from 3matchspecs---
Adding or changing description
The process description in all of these affects the amount of consistency checking and further propagation of results to be done. The default is to check only in the case where the newDesc is an individual (unit, string, etc.) to see if there is a conflicting one, to do standard traps and triggering, and to propagate along those descriptors marked with a meta-description based on the unit for Propagation. See the trace below for examples.
(Describe recipient newDesc processDesc)
recipient is a descriptor used in a special way to control the describe. It can be a unit pointer, unit coreference, slot coreference or specification, or a recursive nesting of these as long as the inntermost description is a unit coreference. Describe works its way from inside out. This is necessary for sensible use of Augment and ReDescribe.
(Describe \(The foo from a Bar thatIs XX) \YY) is equivalent to
(Describe \XX \(a Bar with foo = YY))
If you want the other possible meaning of the first form above (i.e. find the thing which is \(The foo from a Bar whichIs XX) and describe it as \YY), you have to use the Item form (see below):
(Describe (Item (The foo from a Bar whichIs XX)) \YY)
The following forms are equivalent to the first two above:
(Describe (Item XX) \(A Bar with foo = YY))
(Describe \(The self from XX) \(A Bar with foo = YY))
(Augment recipient newDesc processDesc)
This needs rewriting in terms of compilation???
Like Describe, except that it assumes that the recipient description points to a descriptor which indicates a time-changing set, and does the appropriate addition. Thus, given:
# Bar
foo:↑1 SequenceOf(An Integer) 1: A ChangingSequence
Compiled(Pointer)
# U001
self: A Bar with foo = <1 2 3>
and doing:
(Augment \(The foo from a Bar thatIs U001) 4)
we would get:
# U001
self: A Bar with foo = <1 2 3 4>
If no descriptor (or more than one) can be found with a meta-description consistent with Augment, it searches (using processDesc parameterization) for a template descriptor indicating an initial value. If none is found, an error is signalled. Typically, we would have something like:
||[Bar ↑[a Unit] |[foo = (a ChangingSet with initialValue = <1>)]]
(ReDescribe recipient newDesc processDesc)
Like Augment, except it assumes a single changing value rather than an increasing set.Thus, given:
||[U002 |[self [a Bar with foo = {[an OddInteger]
{17 ↑[a ChangingValueDesc]}}]]]
and doing:
(ReDescribe \(the foo from (a Bar whichIs U002)) 4)
we would get:
||[U002 |[self [a Bar with foo = {[an OddInteger]
{4 ↑[a ChangingValueDesc]}}]]]
(Update recipient processDesc)
Like ReDescribe, except it assumes the new value will be calculated on the basis of information found in the description. Thus, given:
||[U003 |[self [a Bar with
foo = {16 ↑[a ChangingValueDesc with
updateFunction = (LISP SquareOldOne)]}]]]
and doing:
(Update \(the foo from (a Bar whichIs U003)))
we would get:
||[U003 |[self [a Bar with
foo = {256 ↑[a ChangingValueDesc with
updateFunction = (LISP SquareOldOne)]}]]]
Of course, typically the update function will use other information from the unit and the current dynamic enviornment. Note that it expects to find the update information in the actual instance. If not it searches for a descriptor saying how to change, and sets one up using the initial value. Typically, we would have something like:
||[Bar ↑[a Unit] |[foo = (a ChangingValue with
initialValue = 2
updateFunction = (LISP SquareOldOne))]]
Thoughts on describe
Sets up mappings like Match
At toplevel, there is simple signal for adding descriptor
Has an embedding world, also a meta-description
e.g. for linking assertions to their consequences
Consistency check hooks
actual check for some cases -- conflicting individuals
Saving up of folded mapping?
What about removing descriptions not originaly put in as changing?
removing items from sets?
other issues for describe
Internal status of entities and mappings
Interaction with description spaces
Updating things which are distributed at read-in time
Process descriptions known to the system
Structure of the code
Searching for descriptions or objects
(Seek source descFilter processDesc)
Returns a description (closed) which is a composite based on starting with the source description, and filtering out descriptors on the basis of the descFilter and the current World description. Null descFilter means to get all the descriptions compatible with the world. The source is a description, and the default (which can be overriden by the processDesc is to go one level:
If source is:Look at:
Unit pointer or coreferenceSelf description
Slot coreferenceSlot description
SpecificationFiller description
e.g. (Seek \(the foo from (a Bar whichIs U002))
\(a ChangingValueDesc)) returns
{17 ↑[a ChangingValueDesc]}
while (Seek \(the foo from (a Bar whichIs U002))
\(Not \(a ChangingValueDesc))) returns
{[an OddInteger]}
(SeekItem source processDesc)
Equivalent to (Seek source \(an IndividualDescriptor) processDesc)) followed by returning the resulting descriptor if it is a string or number, or the corresponding LISP object or Unit if it is a reference to one, where IndividualDescriptor is defined as a string, number, LISP descriptor or unit coreference.
(SeekEach source descFilter action processDesc)
Like seek, except that instead of building a description to be returned, it calls action on each descriptor which would have gone into it.
The LISP form (Item itemDesc processDesc) has as its value the unit, string, number, or lispEntity found by:
1: doing a MakeKRL on the two Desc forms
2: doing a seek with the corresponding item and match descriptions, and with a descriptionDescr which matches lispentities, strings, and unit coreferences (what about slot coreferences?)
3: peeling the item out of the descriptor and returning it as a pointer
If processDesc is NIL, it does a simple local Seek
If no item is found, or more than one, an appropriate signal is sent -- default simply returns NIL in both cases
other issues for Seek
Internal status of entities and mappings
GetItem, Item, ItemSequence
Interaction with description spaces
Descriptor descriptions known to the system
Process descriptions known to the system
Structure of the code
Matching
(Match pattern datum processDesc)
Like previous versions except for changes in processDesc and lack of substitutions, as noted above. Returns a measure of goodness of the match (as determined by the ProcessDesc. Defaults are NIL (no match),....
(CompareMatch patternList datum processDesc) or
(CompareMatch pattern datumList processDesc)
There is either a list of patterns or a list of datums, not both. Returns some structure (to be determined) ordering and/or rating the candidates. Note the asymmetry -- pattern and datum are not treated identically.
(BestMatch patternList datum processDesc) or
(BestMatch pattern datumList processDesc)
Equivalent to a CompareMatch followed by a function which uses the rating structure to pick a single item and return it (as determined by the processDesc)
(MatchSelect patternPairs datum processDesc) or
(MatchSelect pattern datumPairs processDesc)
Like a SELECTQ. Pairs (of either type -- note asymmetry again) are of description followed by LISP code to be evaluated. Default is to take the first one which returns non-NIL match (i.e. ordering is significant). Other regimes (such as a full-fledged bestMatch) can be provided through the processDesc.
Internal status of entities and mappings
Interaction with description spaces
Specifying match bindings
Locality and inheritance
Within a unit, all descriptions are local. Some of them may specify the existence of mappings which involve other contexts. Depending on the type of the mapping, the further descriptions available by interpreting the mapping will be classifed as either immediate or remote. In general, immediate descriptions can be followed without worse than a linear search, while remote ones involve exponential search or arbitrary computations.
Getting the values back
Residues
Process descriptions known to the system
Structure of the code
Structure Specifiers
The form (Describe desc1 desc2 processDesc) works its way from inside out on desc1.
(Describe \(the foo from (a Bar whichIs XX)) \YY) is equivalent to
(Describe \XX \(a Bar with foo = YY))
desc1 must be a unit pointer, unit coreference, slot coreference or specification. If you want the other possible meaning of the first form above, you have to type:
(Describe (it (the foo from (a Bar whichIs XX))) \YY)
The following forms are equivalent to the first two above:
(Describe (it XX) \(a Bar with foo = YY))
(Describe \(slot self of XX) \(a Bar with foo = YY))
This is also true for augment, redescribe, update, etc.
6.3. The top-level functions
There is one basic top-level function, Align, and a number of others (Seek, SeekAll, SeekMy, AddElement, AddDescriptor, SubsituteElement, SubstituteDescriptor, Describe and Overwrite) defined in terms of it for specifying simple cases. They are all CLISP forms which treat their arguments as though they were arguments to a normal lambda -- i.e. they are evaluated before being used. We will take each of these in turn.
(Align datum pattern matchTable)
The pattern and datum must be a handles to an anchor or descriptor. Note that a nexus appearing in the code will evaluate to such a handle. The match table must be a signal table with responses for the signals generated in the matcher. If it is NIL (or absent), a default match table is used -- see section on the Standard Tables below. In order for the access compiler to recognize combinations of standard tables, the pseudo-function MatchTable (which is equivalent to append) can be used. For example, (Align x y (MatchTable DescribeSF UseServantsSF CanMatchSF)) would do an Align with a table made up of those three standard tables.
The pattern can contain meta-descriptions specifying actions to be taken and variables to be bound (see section 7.1 below). For every successful match (see section on multiple-matches below), after the match is complete, all of the actions are taken.
The value returned by Align is determined by a signal. In the simplest case, it is a list of binding sets, one for each successful match. Each binding set is an A-list of variable name and value. This means that NIL is returned if the match was not successful. If no bindings were specified in the pattern, the value is a NIL binding set for each successful match. Thus a successful simple single match produces (NIL)
(Seek valueType groundingPath matchTable)
It is often much more convenient to think about the process of Seeking as working from a single description. Instead of saying "See if Danny is a person with last name = a name with first letter = <the thing I want to bind>", it is clearer to say "Find the first letter from a name that is the last name from a Person thatIs Danny". The thing which is the datum for the alignment (Danny in this case) appears inside a nesting of map descriptors, the thing to be bound is the anchor at the top of the nesting, and the pattern to be used is a kind of "unwinding" of the nesting, in which each map descriptor is grabbed from the other end -- e.g. the descriptor "the lastName from a person thatIs ..." in the seek specification becomes "A person with lastName = ..." in the pattern to be aligned. The full definition of just what kind of nesting is allowed (and special treatment of set membership) isn’t here, partly because we want to coordinate with the cases Rich has done so far in the access compiler.
(SeekAll valueType groundingPath matchTable)
Like Seek, but looks for all values as a list. See example below
(SeekMy valueType slotName matchTable)
This can be used only in the environment of a trigger activation. It is approximately equivalent to a Seek in which the grounding path is: The slotName from a <unit in which the trigger appears> thatIs <instance for which the triggering took place>. It gets this from the free variable environment, not lexically, so a trigger can call a function which in turn uses SeekMy (unstructured, but useful). In fact, it is slightly more general since the instance for which the triggering took place may not be a labelled anchor, but may be an unlabelled anchor or an effective description.
(Describe groundingPath newDesc matchTable)
Like Seek, but with an action of adding the pattern argument as a description in the place where the sought thing was found -- see example below.
The following set of top-level forms correspond to their corresponding action forms (described in 7.1) in the same way as Seek and Describe. Those forms which take either Anchors or Descriptors (e.g. MetaDescribe) can be used in this way only when their arguments are Anchors. Those which appear either on the anchor for the enumeration as a whole, or an individual element (e.g. AddBefore) can be used only when applied to the enumeration anchor. The grounding path cannot be used to indicate a descriptor or an element of an enumeration.
(Overwrite groundingPath newDesc matchTable)
(MetaDescribe groundingPath newDesc matchTable)
(Substitute groundingPath newAnchor matchTable)
(AddDescriptor groundingPath newDescriptor matchTable)
(SubstituteDescriptor groundingPath newDescriptor test count matchTable)
(AddElement groundingPath newAnchor matchTable)
(AddBefore groundingPath newAnchor test count matchTable)
(AddAfter groundingPath newAnchor test count matchTable)
(SubstituteElement groundingPath newAnchor test count matchTable)
(SeekElement groundingPath pattern test count matchTable)
(SeekDescriptor groundingPath pattern test count matchTable)
6.4. Some examples of calls to the matcher
Units used in the examples
# Person father: hometown: firstName: middleName: lastName:
# Family father: children: SetOf(A Person)
# Danny
self: A Person with
father = Jack
firstName = "Danny"
lastName = "Bobrow"
The father from a Family with children = {Kim, Debby, Jordy}
The father from a Child thatIs Kim
The father from a Child thatIs Debby
# Kim self: A Person with lastName = "Bobrow" age = 13
# Debby self: A Person with age = 9
# PaloAlto
self: The hometown from a Person with
firstName = "Danny"
lastName = "Bobrow"
thatIs Danny
The hometown from a Person thatIs Kim
The hometown from a Person with lastName = "Jones"
The hometown from a Person with lastName = "Smith"
The hometown from a Person with lastName = "Bobrow"
=======================
(Align \$Danny:self \A Person with father = @Do(’(Bind x Primary))/ SimpleSeekSF)
==> \$Jack:self
(Seek ’Primary \The father from a Person thatIs Danny/)
==> \$Jack:self
=======================
(Align \$PaloAlto:self
\The homeTown from a Person with lastName = @Do(’(Bind x Pointer))/
MultipleSeekSf)
==> ("Bobrow" "Bobrow" "Jones" "Smith" "Bobrow" )
(SeekAll ’Pointer \The lastName from a Person with homeTown = PaloAlto/)
==> ("Bobrow" "Bobrow" "Jones" "Smith" "Bobrow" )
=======================
(Align \$PaloAlto:self \The homeTown from
a Person with
lastName = "Bobrow"
firstName = "Danny"
middleName = @Do(’(Describe \A RussianName/))/)
==> (NIL)
(Describe \The middleName from a Person with
lastName = "Bobrow"
firstName = "Danny"
homeTown = PaloAlto/
\A RussianName/)
==> (NIL)
=======================
(Align (ValueOf ’x (Align \$PaloAlto:self
\The homeTown from
a Person with
lastName = "Bobrow"
firstName = "Danny"
self = @Do(’(Bind x Primary))/))
\A Person with middleName = @Do(’(Add \A RussianName/))/)
==> (NIL)
(Describe \The middleName from
a Person thatIs !Reference (Seek ’Primary
\A Person with
lastName = "Bobrow"
firstName = "Danny"
homeTown = PaloAlto/)
\A RussianName/)
==> (NIL)
=======================
(Align \$Danny:self \The father from a Family with
children = @Do(’(BindElement x Primary T ALL)))/)
==> (((x \$Kim:self \$Debby:self \$Jordy:self))))
(SeekElement ’Primary \The children from a Family with father = Danny/ T ALL)
==> (\$Kim:self \$Debby:self \$Jordy:self)
=======================
(Align \$Danny:self
\The father from a Child thatIs @Do(’(Bind x Primary)))/
MultipleMatchSF)
==> (((x . \$Kim:self)) ((x . \$Debby:self)))
(SeekAll ’Primary \A Child with father = Danny/)
==> (\$Kim:self \$Debby:self)
=======================
(Align \$Danny:self
\The father from a Child with
self = @Do(’(Bind x Primary))
age = @Do(’(Bind y Pointer))/
MultipleMatchSF)
==> (((x : \$Kim:self)(y : 13)) ((x : \$Debby:self)(y : 9)) )
no simplified form exists
=======================
# Column
self:↑11: Trigger(ToPrint, ’(For x in ’(top bottom sum)
do (PRINT(SeekMy ’Pointer x DoAFancyMatchST))))
top: An Integer
bottom: An Integer
sum:↑2 An Integer2: Trigger(ToFill, ’(LispForSum))
DEFINEQ((LispForSum()
(PROG ((top(SeekMy ’Pointer ’top)) (bottom(SeekMy ’Pointer ’bottom)))
(RETURN(AND top bottom (PLUS top bottom)]
=======================
# Column↑11: Comment("A cleaner version which also works")
top: An Integer
bottom: An Integer
sum:↑2 An Integer2: Trigger(ToFill, ’(LispForSum <(SeekMy ’Pointer ’top)
(SeekMy ’Pointer ’bottom)>)
DEFINEQ((LispForSum
(LAMBDA (L) (AND (EVERY L ’NUMBERP) (APPLY ’PLUS L]
=======================