Page Numbers: Yes First Page: 1
Heading:
April 26, 1979 7:20 PM[IFS]<KRL>document>match-attach
7.2 Procedural Attachment -- Triggers and traps
Triggers and traps are very much like they were in KRL-0. There is a small fixed set of names recognized by the system when attached in a trigger or trap footnote. The cataloguer (see Section ?) stores an index of triggers so they can be used without accessing the prototype unit each time. The comunication between a trigger or trap and its environment is through free variables. Some of these (e.g. the triggering unit, slot, etc.) are general to all triggers or all traps. Others are specific to individual ones.
7.2.1 Triggers
Each trigger (demon or servant) is indexed under one or more labelled anchors (unit and slot name). It is entered through a Trigger meta-description on that anchor (or by being put on dynamically with the functions for manipulating the procedural attachment index). One minor extension beyond KRL-0 is that a trigger can be simultaneously associated with a set of slots in a single unit, through a TriggerOnAny meta-description on the unit.
Whenever a trigger is invoked, the following free variables are available:
SLOT: a handle to the slot anchor for the slot under which the trigger is indexed. In the case of a TriggerOnAny, it is the slot corresponding to the actual instance of triggering
PROTOTYPE: a handle to the self slot of the unit in which the trigger is indexed.
INSTANCE: a handle to an anchor for the instance of the prototype unit in which the trigger appeared
WORLD: a handle to an anchor describing the world corresponding to the goal. If it is the default world, it will be NIL
FULLALIGN: T if the full matcher environment, NIL if called by an access-compiled Align.
As mentioned in section 1.4, the function SeekMy accesses these. I don’t think SeekMy has been written yet.
7.2.1.1 Servants
ToFind: Whenever a Find goal (e.g. FindPost) is activated on a datum which includes a mapDescriptor whose template focus slot includes a ToFind trigger, or it is in that slot of a pattern mapDescriptor, and if the goal is not immediately satisfied by the effective description, then the trigger code is executed.
Note the two cases: Assume \$Foo:bar has a ToFind trigger. Then in the first case, the pattern is:
\A Foo with bar = @Do(’(Bind x Post))/ and the datum is:
\A Foo with mumble = .../.
In the second case, the pattern is:
\A Randomness with stuff = @Do(’(Bind x Post))/ and the datum is:
\A Randomness with stuff = The bar from a Foo with mumble = .../
The variable TYPE is bound to the descriptor the type of binding sought. In a FullAlign, the variable GOAL is set to the appropriate Goal. The value returned by the trigger is treated as follows:
The atom NOTFOUND --> the servant failed to find the desired thing
Any other Lisp pointer --> if the TYPE sought was Post or Lisp, then use it. Otherwise an error (KHelp).
A handle --> if the TYPE sought was Post, and it is a primary anchor handle, use it as coreference. If it is a handle to a KRL-pointer descriptor and the type was Post, use its contents in a KRL-pointer. If the type was KRL and it was a handle, use it directly in a KRL-pointer. If the type is Primary or Anchor and it is a handle of the right kind, use it. Otherwise an error (KHelp).
Note that if the code does not end up satisfying the goal, it will not be tried again unless a new descriptor is found which has that slot as its focus slot..
ToEnumerate: Like ToFind, except for a FindEnumeration goal. Value returned must be the atom NOTFOUND, or a list of elements treated as described above. Note that finding a primary anchor for a collection is different from being able to enumerate its elements.
ToMatch: Whenever an AlignMapDescriptor goal is activated and not immediately satisfied, the system looks for a ToMatch trigger associated with the focus slot of the prototype unit, and runs the code. The variable PATTERNDESCRIPTOR will be bound to the pattern descriptor (which is a map descriptor whose unit and focus correspond to the place the trigger is indexed). DATUM is bound to the corresponding datum anchor. The variable FOCUSMATCHED is non-NIL if it is known that the map descriptor focus applies, but the fillers have not been all matched, NIL if nothing has been proved about the match. The trigger is expected to return a value like a signal:
ALLOK -> assume the goal is satisfied
OK -> assume that the focus is satisfied, but go ahead and set up subgoals for the individual fillers. Notice that if FOCUSMATCHED is non-NIL, then this answer is irrelevant.
SKIP -> the trigger didn’t satisfy it (although it may have acted through side effects on the environment) but go on trying
FAIL -> the goal fails -- no match should be sought
As with ToFind, this trigger will not be tried again unless it is provoked by a new map descriptor with appropriate focus slot.
7.2.1.2 Demons
As mentioned in section 6.2, the actions associated with a call to Align are all saved up until the match is complete (with all bindings), then done. The triggering of demons is done at this time, and the code has access to the entire list of actions. Demons for each kind of event (e.g. filled, described, etc.) are of two types -- those which are done before the action actually happens (e.g. BeforeFilled), and those that happen afterwards (e.g. WhenFilled). The process carried out for each successful result of the Align is as follows:
For each action (the result of a single Do functional or a place in a Describe where something was actually added), do the following:
Find all the potential demons which will fire.
Execute each of the Before... demons.
Do the actual structure changes corresponding to the action
Execute each of the When... demons.
The demons associated with any one action are taken in arbitrary order. If a Before.. demon wants to prevent the action from being taken, it can call modify the action by setting its actionSpec to NIL. This will prevent it from being done, and from being used as a cause for When... demon invocation. Code which depends on any fancy timing between actions and demons is taking its chances.
When a demon is invoked, the following variables are always bound:
TRIGGERFORM or TRAPFORM: One or the other will be bound, depending on whether the demon is a trap or trigger. It is bound to a record of that same type (TriggerForm or TrapForm), which is the one causing the firing.
ACTION: The top-level action (a record of type Action) which provoked this demon, possibly through its sub-actions.
ALLACTIONS: A list of all the sub-actions (including the top-level actions) provoked by ACTION
ACTIONS: A list of the sub-actions which provoked this particular demon.
PATH: An anchor path, which is the thing on which the action will be taken. The change is to the CAR of the path. The path is an alternating list of Anchors and Descriptors, such that PATH:n is a structure which is a part of PATH:(n+1).
TRIGGERS: All of the triggerforms for ACTION. This includes one for every case where either a Before.. or a When.. trigger exists, and is not modified as they are done, so it includes all those which have been and will yet be done.
TRAPS: like TRIGGERS
OLDACTIONS: Actions (siblings of ACTION) which have already been done
NEWACTIONS: Actions yet to be done. ACTION is on neither of these lists.
Demons which are triggers
The following variables are bound when a trigger demon is invoked:
PROTOTYPE: The self slot of the unit in which the trigger appears
SLOT: The slot which caused the triggering
INSTANCE: An anchor for an instance of PROTOTYPE for which the triggering occured.
WORLD: The world for the instance
MAPDESCRIPTOR: The map descriptor which caused the triggering. In the case of a *Identified, it will be the new descriptor being added. In a *Filled, *Described, or *EnumerationChanged, it will be somewhere in the PATH above the place where the change is being made.
The following are the different trigger demon types:
*Filled: This trigger is activated whenever an action is taken meeting the following criteria:
1. A CoReference to a primary anchor, LispPointer, or KRLpointer is added to an anchor which did not previously contain it
2. The anchor in which it is put is the filler anchor for a perspective of the prototype for which the trigger is indexed, in a pair for the slot on which it is indexed.
The variable FILLER is bound to the post corresponding to the descriptor added (i.e. the actual lisp pointer, KRL handle, or structure Descriptor). PATH:1 is the anchor in which it is being put, PATH:2 is the entire mapDescriptor, and path:3 the anchor in which it appears.
Note that this covers several cases in addition to the simplest one. For example, it does not insist that the mapDescriptor have SELF as its focus slot. If we had in some anchor a previous description \The bar from a Foo/ and add the description \The bar from a Foo with mumble = 3/, a WhenFilled on \$Foo:mumble would be triggered. Also, there is no condition that the mapDescriptor appear at the top level of a labelled anchor. Thus if we have a datum of \A Foo with bar = A Gritch/ and add \A Foo with bar = A Gritch with yuk = "hello"/, then a WhenFilled on \$Gritch:yuk is activated. The KRL-0 version of WhenFilled corresponds to this one when PATH:3 is a primary anchor and PATH:2 has SELF as its focus slot.
WhenEnumerationChanged: This trigger is like WhenFilled, except that the first condition is:
1. A change (addition or deletion) is made to an explicit enumeration descriptor appearing in an anchor, or a new enumeration descriptor is put into an anchor not previously containing one.
In addition to the variables for WhenFilled (except for FILLER, which it does not have), it has ENUMERATION bound to the old enumeration descriptor (or the changed version after the action).
Note that this is structure local -- if something is described as \A Foo with bar = GoodGuys/ and \$GoodGuys:self contains an enumeration, then changes to that enumeration will not trigger a WhenEnumerationChanged on \$Foo:bar.
WhenDescribed: This trigger is activated whenever an action is taken meeting the following criteria:
1. Any change is made to the contents of an anchor
2. That anchor is lexically contained at any depth inside a filler anchor for the indexed slot in a mapDescriptor for the indexed unit
3. The change was made as part of a call to Align whose datum (including that added by describe -- see below) explicitly included the path down from the mapDescriptor to the changed anchor
This is the catch-all trigger for noticing that something is being changed in a structure. Its variables are (in addition to the standard ones for all triggers):
DESCRIPTORS: A list (possibly NIL) of descriptors being added directly to a filler anchor corresponding to the trigger.
CHANGES: A list (possibly NIL) of Actions which cause changes internally to descriptors embedded below the filler anchor.
Note that there is a big difference between a call to align which includes an action on some embedded anchor, and a sequence of two operations, the first of which finds and binds that embedded anchor, and the second of which does something to it. The single call will trigger all of the relevant WhenDescribeds on the chain down to the anchor, while in the separated case, the action will be taken without triggering any demons.
WhenIdentified: This trigger is activated whenever a MapDescriptor with the index slot as focus slot and index unit as prototype is added to an anchor. It will not be triggered when one was already there, and simple folding prevented a new top-level mapDescriptor from being added. However it will be triggered if a second one is added because folding isn’t obvious (e.g. adding a second \The hometown from.../ descriptor to an anchor which has one).
Whereas all of the previous demons in this list were triggered because their attachment correspond to the structure in which changes were made, this one is triggered because it corresponds to the structure being added. Note that unlike WhenIdentified in KRL-0, it does not depend on the anchor to which it is being added being primary -- it is triggered when an appropriate descriptor is added to any anchor (including one embedded in a contingency) it is up to the trigger code to determine the nature of the place it is being added.
*** this is as far as I have gone ***
7.2.2 Traps
Each trap (demon or servant) appears in the meta-description of an anchor and is not otherwise indexed. When it is invoked, the variables available are:
ANCHOR: a handle to the anchor in which the trap appeared
WORLD: a handle to an anchor describing the world corresponding to the goal. If it is the default world, it will be NIL
FULLALIGN: T if the full matcher environment, NIL if called by an access-compiled Align.
7.2.2.1 Servants
ToFind: Whenever a FindBinding goal is activated on an effective description which includes in its procedures a ToFind trap, and if the goal is not immediately satisfied by the effective description, then the trap code is executed.
The variable TYPE is bound to the descriptor the type of binding sought. The value returned by the trap is the same as for the corresponding trigger
ToEnumerate: Like ToFind, except for a FindList goal. Note that finding a primary anchor for a collection is different from being able to enumerate its elements.
7.2.2.2 Demons
WhenFilled: This trap is activated whenever Coreference, LispPointer, or HandleDescriptor is added to the anchor on which it appears (note that it is not inherited by effective descriptions which copy its descriptors). Variable is FILLER, the object filled in (as with the trigger).
WhenEnumerationChanged: As with the trigger, mutatis mutandis
WhenKnown: When this anchor is the structural grounding of an effective description to which a Post is added
WhenDescribed: Any change is made at any level (as qualified in the description of the corresponding trigger)
7.3 The goal types
For more details on these, see the individual files. Those with stars are not yet written:
FILE: ALIGNCLASSES
AlignAnchor
AlignCoreference (align a non-Primary Coreference)
AlignPost (align a Primary Coreference, LispPointer, or HandleDescriptor)
AlignMapDescUnique (the pattern map descriptor is unique w.r.t. its focus slot)
AlignMapDescMulti (the pattern map descriptor is not unique w.r.t. its focus slot. Alos used for InterpretedMapDescriptors in structural match)
AlignMapDescOneOf (used by both Unique and Multi to match against an individual datum MapDescriptor)
AlignNot
AlignOr
AlignContingency
*AlignContains
*AlignMemberOf
*AlignUsing
*AlignSequenceAny (the pattern contains no explicit elements, so any sequence will do)
*AlignSequenceComplete (the pattern sequence contains no "...")
*AlignSequenceEmpty (the pattern is the empty sequence)
*AlignSequenceMultiGap (the pattern sequence contains more than one "...")
*AlignSequenceOf (the pattern is a SequenceOf functional)
*AlignSequenceSingleGap (the pattern sequence contains a single "...")
*AlignSequenceSingleton (the pattern sequence contains a single element and no "...")
*AlignSetAny (the pattern contains no explicit elements, so any set will do)
*AlignSetComplete (the pattern set contains no "...")
*AlignSetNull (the pattern is the empty set)
*AlignSetIncomplete (the pattern set contains one or more "...")
*AlignSetOf (the pattern is a SetOf functional)
*AlignSetSingleGap (the pattern set contains a single "...")
*AlignSetSingleton (the pattern set contains a single element and no "...")
FILE: FINDCLASSES
FindAnchor
FindDescriptors
FindElements (used within a single enumeration descriptor)
FindEnumeration (used to find the enumeration descriptor in which elements are sought)
FindPost (find a Primary, Pointer, or Hook)