Earlier I asked for criticisms of LIB NEWPSYS and suggestions for
extensions.
I have a minor concern that accessing or updating global Pop-11
variables in conditions and actions of rules should have been made
easier. At present one can use these syntax form embedded in patterns
or actions:
[apply valof var]
or
[apply uvalof val var]
after doing, globally updater(valof)->uvalof
Alternatively [popval ...] can be used, though at greater cost, since
this compiles and runs a procedure every time the item is interpreted.
It would have been nicer to have more concise syntax like [^ var] and
perhaps [->^ val var]. I'll think about extending NEWPSYS.
A more important idea is to extend the SAVE and RESTORE actions, which I
have now done in a draft library called PSYS_EXTRA.
Currently HELP NEWPSYS describes the following means of saving and
restoring the database or the ruleset.
| -- -- SAVE and RESTORE actions
| It is possible to save or restore either the working memory, or the
| ruleset using these actions. The formats available are as follows:
|
| [SAVE RULES <name>]
| Equivalent to: psys_rules -> valof(<name>)
|
| [SAVE DATA <name>]
| Equivalent to: psys_database -> valof(<name>)
|
| [RESTORE RULES <name>]
| Equivalent to: valof(<name>) -> psys_rules
|
| [RESTORE DATA <name>]
| Equivalent to: valof(<name>) -> psys_database
|
| These actions can be combined, as follows:
|
| [SAVE DATA <name1> RULES <name2>]
|
| [RESTORE DATA <name1> RULES <name2>]
|
I wrote previously that I was going to use this in an agent
architecture, as follows:
> We are starting to use NEWPSYS to implement a generic agent architecture
> which can be used in multi-agent "simulations" of various kinds. The key
> idea is that each agent will be composed of a collection of sub-contexts
> each represented by a ruleset and a database. Since switching between
> rulesets and databases is very fast and very simple, representing
> parallelism should be easy, though aspects of timing to ensure
> reasonable relative speeds will need to be thought through.
The trouble is that if you wish to temporarily switch to a new
ruleset or dataset and then restore the previous one using the
existing mechanisms, you have to first save the previous one in some
variable and then restore from that variable. This is too
unstructured (like GOTO?). So I propose an extension allowing nested
invocations of rulesets or databases, as follows.
This extension is easy because LIB NEWPSYS allows the user to define
new action keywords, by associating them with procedures, using the
property psys_action_type.
This sort of extension makes it easier to have a controlling ruleset
that temporarily sets up transfers to other rulesets, which come
back to the controlling set when done. This has obvious analogies
with procedure call and return. By allowing transfer between
databases also, we get the analogue of calling a procedure with some
data which can return data when it finishes.
Here's a rough description of the proposed extension.
-- PUSHRULES, POPRULES, PUSHDATA, and POPDATA actions -------------
-- PUSHRULES ----------------------------------------------------------
[PUSHRULES <ruleset>]
Save current rules on psys_rule_stack, and make <ruleset>
current.
Equivalent to:
psys_rules::psys_rule_stack -> psys_rule_stack;
<ruleset> -> psys_rules;
(If <ruleset> is just a word, it uses valof, otherwise
the whole expression is evaluated using compile).
-- POPRULES -----------------------------------------------------------
[POPRULES]
Restores previous ruleset.
Equivalent to:
destpair(psys_rule_stack) -> (psys_rules, psys_rule_stack)
[POPRULES <ruleset>]
As above, but first saves current ruleset as specified.
The <ruleset> specification could be a single word, in which
case -> valof(word) is used, or else a more complex
specification, e.g. "lastrules(myself)", in which case the code
psys_rules -> lastrules(myself)
will be used.
-- PUSHDATA -----------------------------------------------------------
[PUSHDATA <database>]
Save current database on a stack, and make <database>
current.
Equivalent to:
psys_database::psys_data_stack -> psys_data_stack;
<database> -> psys_database;
(If <database> is just a word, it uses valof, otherwise
the whole expression is evaluated using compile).
[PUSHDATA [<patternlist>] <database>]
If [<patternlist>] is present then all items matching the
pattern are transferred from the initial database to the
new one. (They are removed from the initial one). If the
database pushed is empty, then the new database will contain
only items matching those in patternlist.
-- POPDATA ------------------------------------------------------------
[POPDATA]
Restores previous database.
Equivalent to:
destpair(psys_data_stack)
-> (psys_database, psys_data_stack)
[POPDATA [<patternlist>] ]
If [<patternlist>] is present then all items matching the
pattern are transferred from the initial database to the
new one. (They are removed from the initial one).
[POPDATA <database>]
[POPDATA [<patternlist>] <database>]
As above, but allows current database to be saved as specified,
These action forms would help with implementation of a SOAR-like
system, among other things.
All these action forms are quite easy to add to LIB NEWPSYS.
For example, something like the following will define the PUSHRULE
action type:
-------------------------------------------------------------------
global vars psys_rule_stack = [];
;;;; (or make it lvars if it is not to be accessible to users)
;;; Set up the association with procedure name and action type
;;; (using the name so that the procedure can be traced, or redefined).
"psys_do_PUSHRULES" -> psys_action_type("PUSHRULE");
;;; define the procedure
define psys_do_PUSHRULES(rule_instance, action);
;;; ignore rule_instance in this case
;;; action will be [PUSHRULES <rulespec>]
lvars rule_instance, action, rulespec;
;;; push the current set of rules onto the rule stack
psys_rules::psys_rule_stack -> psys_rule_stack;
;;; Now install the new set of rules
back(action) -> rulespec;
if back(rulespec) == [] then
;;; it's a one-element list
recursive_valof(front(rulespec))
else
compile(rulespec)
endif -> psys_rules
enddefine;
(My version is a bit more complex as it does some checks.)
Similar things can be done to define PUSHDATA, POPRULES, POPDATA, using
a separate stack for the databases.
I have a draft library LIB PSYS_EXTRA which provides the
extensions described above, and if anyone is interested to look at
it, please let me know (or I could post it -- currently about 325 lines
including about 45% documentation). But it is not yet tested.
Later it will go into our ftp directory:
ftp://ftp.cs.bham.ac.uk/pub/dist/poplog/
as lib/psys_extra.p
Comments, suggestions welcome
Aaron
--
Aaron Sloman,
School of Computer Science, The University of Birmingham, B15 2TT, England
EMAIL A.Sloman@cs.bham.ac.uk OR A.Sloman@bham.ac.uk
Phone: +44-(0)21-414-4775 Fax: +44-(0)21-414-4281
|