Dialog context
The dialog context is a simple memory module that contains the inferences that are made during the processing of the sentence and that are stored during the remainder of the dialog.
(‘dialog_isa’, reified-variable, class-name)
dialog_isa is a the predicate “isa” in the context of a dialog. It says “variable e1 is part this class”. The variable is a “reified dialog variable”, ie the name of a variable, written in lowercase: for example e1.
Here’s an example of an atom that is stored in the dialog context:
{
"syn": "noun(E1) -> 'river'",
"sem": lambda: [('river', E1)],
"dialog": [('dialog_isa', e1, 'river')]
}
The atoms are in the dialog field. The atom here, ('dialog_isa', e1, 'river') says: “e1 is a river”. When this sentence is composed by the Composer, it stores this fact in the dialog context. From that point it is available by all modules like any other tuple in a database.
Why would you create both a sem and an inf for the same information, that E1 is a river? The sem is used to filter out the E1s that are not a river. The inf is used to provide information to predicates elsewhere in the sentence, or even in sentences further up in the dialog. For example, here is the predicate has_population:
def has_population(self, values: list, context: ExecutionContext) -> list[list]:
term = context.arguments[0]
type = ""
if isinstance(term, Variable):
isa = context.solver.solve1([('isa', term.name, Variable('Type'))])
if isa is not None:
type = isa["Type"]
if type == 'city':
out_values = self.ds.select("city", ["id", "population"], values)
out_values = [[row[0], row[1] * 1000] for row in out_values]
else:
out_values = self.ds.select("country", ["id", "population"], values)
out_values = [[row[0], row[1] * 1000000] for row in out_values]
return out_values
If E1 is a city, has_population needs to retrieve its size form the city table. If it’s a country, it comes from the country table.
Dialog variables
The variables E1, E2, E3 etc are limited in scope to the rule itself. When the sentence is composed, these variables unified and turned into dialog variables $1, $2, $3 etc. Each new entity gets its own dialog variable. Numbering doesn’t restart at a new sentence, it just continues with $4, $5, $6.
Reified variables
The facts inferred from the sentence are stored in the dialog context. However, it is not possible to store ('isa', E1, 'river') in the database, since E1 is a variable! Still, we want to store information about the variable, rather than one of its bindings, in the database. To do that the variable is turned into a string with the same name. This is making an abstract entity concrete, or reification. The result is ('isa', e1, 'river'). Note the lower cased e1.
(‘with_context’, name, )
The context module has a means of starting a context in the dialog. This for example how to start a context called “question”:
[('with_context', 'question', [('intent_yn', proper_noun1 + proper_noun2 + preposition)])]
This context can be used by inference rules:
# in the context of a question, left_of is transitive
left_of(A, B) :- context('question'), just_left_of(A, B).
left_of(A, B) :- context('question'), just_left_of(A, C), left_of(C, B).
left_of(A, B) :- context('question'), just_left_of(C, B), left_of(A, C).
Todo: the syntax of the context in the inference should be simpler