Representing Places
To understand what we need to properly represent places, let’s go through a key predication from the ERG that represents place, loc_nonsp
.
loc_nonsp
(“nonspecific location”) is true when x_location
represents a “place” where x_actor
“is” or “is at” but doesn’t get more specific than that. It shows up in phrases like:
- “Where am I?” -> no relationship other than I “am” somewhere
- “Where is the stick?” -> no relationship other than the stick “is” somewhere
- “The dog barks every day” -> No relationship to day other than it “happens” every day
It would not show up in phrases that more specifically locate something, such as:
- The stick is on the table. -> locates the stick in a place on the location
- He arrives before/at 10am. -> locates the arrival before/at a certain time
More information is available in the ERG reference.
In this topic, we’ll implement the loc_nonsp
and place_n
predications to make the phrase “Where am I?” work. As always, we’ll start by trying out the phrase, even though we know it won’t work yet, and using /show
to examine the MRS to see what predications it generates:
? where am I?
I don't know the words: where, I
? /show
User Input: where am I?
1 Parses
***** CHOSEN Parse #0:
Sentence Force: ques
[ "where am I?"
TOP: h0
INDEX: e2 [ e SF: ques TENSE: pres MOOD: indicative PROG: - PERF: - ]
RELS: < [ loc_nonsp<0:5> LBL: h1 ARG0: e2 ARG1: x3 [ x PERS: 1 NUM: sg IND: + PT: std ] ARG2: x4 [ x PERS: 3 NUM: sg ] ]
[ place_n<0:5> LBL: h5 ARG0: x4 ]
[ which_q<0:5> LBL: h6 ARG0: x4 RSTR: h7 BODY: h8 ]
[ pron<9:10> LBL: h9 ARG0: x3 ]
[ pronoun_q<9:10> LBL: h10 ARG0: x3 RSTR: h11 BODY: h12 ] >
HCONS: < h0 qeq h1 h7 qeq h5 h11 qeq h9 > ]
-- CHOSEN Parse #0, CHOSEN Tree #0:
┌────── place_n(x4)
which_q(x4,RSTR,BODY) ┌────── pron(x3)
└─ pronoun_q(x3,RSTR,BODY)
└─ loc_nonsp(e2,x3,x4)
place_n(x)
As in “Where am I?”, place_n
often appears with loc_nonsp
when the location being referred to is inferred by the ERG to be a place.
What are the “places” in a file system? They are all the objects where something else can be located, some obvious ones:
file
: text can be located in a file, “where is the text ‘summary of costs’?”folder
: files can be in a folder, “where is the file ‘foo.txt’?”
For this particular system, a good proxy for “place” might be anything that something can be “in”, aka a “container”. We’ll want easy ways to:
- Find all the containers
- Find all the containers that contain a particular thing
place_n
will be able to leverage the methods on the objects we built in the previous section to do this, and we’ll use the same approach we’ve been using for other nouns introduced in the Implementing a Predication topic:
@Predication(vocabulary)
def place_n(context, state, x_binding):
def bound_variable(value):
# Any object is a "place" as long as it can contain things
if hasattr(value, "contained_items"):
return True
else:
context.report_error(["valueIsNotX", value, x_binding.variable.name])
return False
def unbound_variable():
for item in state.all_individuals():
if bound_variable(item):
yield item
yield from combinatorial_predication_1(context,
state,
x_binding,
bound_variable,
unbound_variable)
This should all look reasonably familiar by now. If an object has a contained_items
method, that means it is a container and that means it is “a place”. Different systems will have different criteria for place depending on their scenarios. The function iterates through all objects in the system and yields any that have this method when its x
argument is unbound, thus yielding all the “places”.
loc_nonsp(e,x,x)
: Representing Generic Location
As described above, loc_nonsp(e,x_actor,x_location)
is true when x_location
represents a “place” where x_actor
“is” or “is at” but doesn’t get more specific than that. Basically, it is the “generic location” of x_actor
(x_actor
does not need to be an actually be an Actor
it can be anything). This means we’ll need to get the “location” from the objects in the system. Note that a given file or folder has many “locations”:
- It is located in a folder
- It is also located in the parent folder
- It is also located in the parent of the parent folder
- etc.
We’ve already implemented a method to return the locations of objects called all_locations()
on the Actor
, File
and Folder
objects which we can use:
@Predication(vocabulary, names=["loc_nonsp"])
def loc_nonsp(context, state, e_introduced_binding, x_actor_binding, x_location_binding):
def item_at_item(item1, item2):
if hasattr(item1, "all_locations"):
# Asking if a location of item1 is at item2
for location in item1.all_locations(x_actor_binding.variable):
if location == item2:
return True
context.report_error(["thingHasNoLocation", x_actor_binding.variable.name, x_location_binding.variable.name])
return False
def location_unbound_values(actor_value):
# This is a "where is actor?" type query since no location specified (x_location_binding was unbound)
# Order matters, so all_locations needs to return the best answer first
if hasattr(actor_value, "all_locations"):
for location in actor_value.all_locations(x_actor_binding.variable):
yield location
context.report_error(["thingHasNoLocation", x_actor_binding.variable.name, x_location_binding.variable.name])
def actor_unbound_values(location_value):
# This is a "what is at x?" type query since no actor specified (x_actor_binding was unbound)
# Order matters, so all_locations needs to return the best answer first
if hasattr(location_value, "contained_items"):
for actor in location_value.contained_items(x_location_binding.variable):
yield actor
context.report_error(["thingIsNotContainer", x_location_binding.variable.name])
yield from in_style_predication_2(context,
state,
x_actor_binding,
x_location_binding,
item_at_item,
actor_unbound_values,
location_unbound_values)
loc_nonsp
is an “in-style” predication because if the location of x
is location1
and the location of y
is location
, then they are both there “together” or “separately” and it doesn’t mean anything special, but also shouldn’t be prohibited. This is a pretty straightforward implementation, just like the implementation of _in_p_loc
in the In-Style Predications topic.
We’ve introduced two new location-based errors thingHasNoLocation
and thingIsNotContainer
, so we need to provide messages for them in generate_custom_message()
as well (using s-strings):
def generate_custom_message(tree_info, error_term):
...
elif error_constant == "thingHasNoLocation":
return s("{arg1} is not in {arg2}", tree_info)
elif error_constant == "thingIsNotContainer":
return s("{arg1} can't contain things", tree_info)
...
Example
Including the implementation of loc_nonsp
and place_n
, with no other changes to the code we’ve built so far, allows us to start interacting with place a bit:
python hello_world.py
? where am I?
(Folder(name=/documents, size=0),)
(there are more)
? where are you?
you is not in place
? where is a file?
(Folder(name=/documents, size=0),)
(there are more)
? where is a folder?
(Folder(name=/, size=0),)
(there are more)
Both “where am I?” and “where is a file/folder?” give an answer and then say, “(there are more)”. That is because the user asked for “a place” (singular) but most things will “be located” in more than one place. For example, the user is in both “/documents” and “/” (the root directory). As described in the Optimizing Solution Groups topic, we let the user know if they there is more than one thing if they ask for a singular answer, just to clarify.
Also note that “you” refers to “the computer” and we haven’t put it anywhere, that’s why the system responds with “you is not in place”. Again, we’ll fix the English on error messages soon.
Comprehensive source for the completed tutorial is available here
Last update: 2024-10-25 by Eric Zinda [edit]