With help from many in this Discourse (thank you!), I’ve got a simple prototype working that uses the ERG to parse English into a logic form and a Prolog engine to process the result. I thought I’d show you all what I got working! First is a “demo” and then an overview of how it works.
Example Transcript
Here’s an example interaction. Everything after a “?” is something I typed, the responses follow. The “scenario” is a cave system with two caves connected to each other. First cave is an entrance but it doesn’t have a name, second cave is called Plage. There is a diamond in the entrance cave and two rocks in Plage. It also knows about one pronoun (You), and a few facts about the world in general.
? Where are you?
Where = entrancecave? What do you see?
What = diamond1? Do you see a rock?
No? Where is the rock?
there is more than one of those? Where is a rock?
Where = plage? go to Plage
OK? do you see a rock?
Yes? are you a person?
Yes? are you a Donkey?
No? Where are the Donkeys?
there aren’t any? is the diamond in the entrance?
Yes
System Overview
There is a relatively simple translation layer that takes the predicate logic output of the ERG and converts it to Prolog terms. Obviously, I had to define each of these terms in Prolog. As an example:
“Where is the diamond?”
is translated into this logical form by doing a depth-first walk of one of the solutions output by the ERG:
Logic: _the_q(x3, _diamond_n_1(x3), which_q(x4, place_n(x4), loc_nonsp(e2, x3, x4)))
which gets converted into this Prolog form by doing some mappings:
Prolog: =(CreateOrEval, create), =(E9052, id9056), d_the_q(conj(d_noun(diamond, X9053), conj(isInstance(X9053)))), d_noun(place, X9054), d_loc_nonsp(E9052, X9053, X9054, CreateOrEval).
- Non-quantifiers are trivial mappings
- Quantifiers are more complicated. For example “_the_q” is translated to a predicate called “d_the_q()”
- which fails if it gets more than one thing
- and takes the RSTR in conjunction with a predicate called “isInstance”
- isInstance() ensures results are limited to only actual things in the world, not types in the type hierarchy.
- the predicate “conj()” is just doing boolean conjunction with its arguments
- Probably the least obvious thing is how I’m handling events (still a work in progress). I’m assigning a GUID like “id9056” to each event variable before I send the statement to Prolog. Then, the terms can “do whatever they need to do” with the event.
- In this example, they don’t do anything, but if a group like “very green” was there, “very” would attach some data to the event saying the event was “very”, and then later “green” would see that its event had a degree specified and do the right thing with its x variable.
- “CreateOrEval” is used to tell predicates with event arguments whether they should create or lookup the eventID in the database. Just an implementation detail.
Then, for questions and propositions, the Prolog is just executed and I get a result like below:
CreateOrEval = “create”, E9052 = “id9056”, X9053 = “diamond1”, X9054 = “entrancecave”
For questions with unbound variables like X9054, I just return those as the answer. If it had all bound variables, it would be yes or no depending on if it was true or not.
Commands like “go to X” get dealt with in two passes:
- First pass is just like the above except there is a verb in there somewhere that doesn’t do anything except attach “verb X happened” to the event. Now we have a fully formed event that says something happened in the database.
- Second pass is where “code” runs that grabs that EventID and figures out how to modify the world to make whatever got attached to it be true. If it works, the world is changed and that EventID stays around as a thing that happened that can be asked about.
- The “code” that gets run is actually a planner: a Hierarchical Task Network planner
Anyway, pretty cool to see things working. Next up I’ll be using the ERG to generate more interesting answers!