Contemplating improvements to the built-in testing commands

Blame the world model: the asymmetry of the relation is a direct consequence of the fact that you can have one-way passages.

I’m not complaining about the ability to have one-way passages. I’m implying that I didn’t expect adjacency to depend on the direction of the passage.

It does make some sense when you look at the definition of the adjacent adjective, though. Most of the time you want “adjacent to current location”.

It seems that generic phrases can only define kind variables in 3 ways:

  • The return type (for phrases returning a value)
  • By naming the kind ((name of kind of value K))
  • As a scalar variable ((M - value of kind K)) - where “scalar” means “not of a composite type”

In other words, you cannot declare a kind variable in a non-scalar variable parameter, which means anything like this phrase header is not possible as far as I can tell:

To chart relation (R - relation of values of kind K):

I would probably need to write the phrases like this instead:

To chart relation (R - relation of K) over (name of kind of value K):
To chart relation (R - relation of K to L) over (name of kind of value K) and (name of kind of value L):

Which is fine if the goal is just to define a phrase, but seems like it’ll be a huge barrier in understanding a relation from the parser and selecting the correct phrase to match that relation. I’d hoped there would be a way to invoke phrase-matching from I6 somehow (so that it could select which of the chart relation (R - some sort of relation) phrase best matched the particular relation), but it seems like that’s just not going to work…?

From what I can tell, the relations command just invokes a function that hard-codes a call to loop over each known relation; and the show relation phrase is implemented with a special substitution, {-show-me:}, which I think boils down to the same mechanic that relations uses except only calling one of those functions instead of all of them.

I think the mechanism used by relations should in theory be usable by a custom action to list only a specified relation, but I’m still drawing a blank on how that could be done…

EDIT: Hmm, part of the issue with calculated relations is that the properties are unknown. Is it one-to-one? One-to-various? Reciprocal? Equivalence? You have no idea, so you have to account for the worst-case scenario and treat it as a various-to-various relation. But those properties aren’t something that can really be determined easily. You could theoretically use algebraic properties to derive them from the relation’s definition (for example, the questiness relation is defined in terms of a relation known to be transitive, so I think it can be assumed to be transitive as well), but I’m not sure how you’d do that in code. You can of course iterate over the entire relation to determine them as well, but that’s not helpful when you’re charting the relation, which also requires iterating over it.

I did a check of how complex phrase overloads are compiled down to I6. It appears this just gets inlined into an if/else chain at the call site of the phrase (though, I only tested with a single use, so maybe it would turn into a routine if the phrase were widely used on general variables; I presume using it on a constant just compiles as a direct call the the most applicable phrase).

I think that would make it difficult to leverage for a SHOWRELATION command, but I’m not ready to say it’s impossible.

The IterateRelations routine exists and can take an arbitrary callback, and the array that defines a relation usually includes its name. (To be specific, it includes its name if the first array element is 0.)

So, I think I should be able to craft a callback that gets passed to IterateRelations, which does the following (peudo-code):

  • if the text matched from the player’s command is equal to the name of the current relation[1]:
    • Determine the types involved in the relation[2]
    • Call a routine which selects the best matching form of the chart relation phrase. I think there would be at least 4 different such routines to choose from, but maybe more.

I think the routines in question could be something like this:

To call chart relation on (R - a relation of objects) (this is the object relation charter):
	chart relation R.
To call chart relation on (R - a relation of values to objects) (this is the value-object relation charter):
	chart relation R.
To call chart relation on (R - a relation of objects to values) (this is the object-value relation charter):
	chart relation R.
To call chart relation on (R - a relation of values) (this is the value relation charter):
	chart relation R.

The I6 code generated for those looks like it might work, though I don’t actually understand what it’s doing in any detail. Still, it’s a chain of if/elses, so I think there’s a good chance it would work. There is one big hole in that though – what do I do when the relation’s I6 definition is just Array Rel_Record6 --> [ 1; ];? There’s no name of the relation there, nor a reference to the list of involved kinds. It appears that this relation is compiled from the following source text:

Fliggling relates one thing to one number.
The verb to fliggle means the fliggling relation.
Ben fliggles 3. Lucy fliggles 42.

There are still some missing pieces here, and in particular, all of that seems to imply a lot of code duplication in the chart relation phrase. Charting a relation of objects and a relation of values is pretty much the same thing, after all? So I would’ve liked to be able to write just To chart relation (R - a one-to-one relation of values): and have it work on every type of value, whether object or arithmetic.

But I don’t think that works – although that phrase definition does appear to work on a relation of objects, it won’t compile if I apply it to a relation of objects to values. The compiler does accept To chart relation (R - a one-to-one relation of values to values):, and that does match a relation of objects, but it doesn’t match a relation of objects to values. I’m guessing relation of values to values is actually treated as a synonym for relation of values.

I guess this does at least mean I can probably have only 3 versions of each phrase instead of 4, but it’s still not great… this all fails to handle the mapping relations as well (which, from the looks of it, don’t even have an I6 array definition unless they’re explicitly referenced in the source test), though it wouldn’t be too hard to special-case those by matching the direction instead of the relation. In fact, I already wrote To chart relation (D - a direction), as well as special cases for almost all the spatial relations[3].

If anyone sees any flaws in this outline, feel free to mention them now.


  1. (relation)-->6 ↩︎

  2. ((relation)-->9)-->2 and ((relation)-->9)-->3 ↩︎

  3. Which reminds me, I don’t quite understand what the holding and room-containment relations are, so didn’t write the phrases to chart those; plus I had trouble expressing visibility and touchability, so those phrases also aren’t done. I’ll probably expand on this more soon. ↩︎

Okay, so I’ve already run into a roadblock: I have absolutely no clue how you would compare strings in an I6 include.

This is what I have so far:

Tracing relationships is an action out of world applying to a topic.
Understand "showrelation [text]" as tracing relationships.

Carry out tracing relationships:
	choose appropriate chart relation phrase.

To choose appropriate chart relation phrase: (-
	IterateRelations(ChartRelation);
-).

Include (-
[ ChartRelation rel;
	! this condition obviously doesn't work,
	! but it should be fairly self-explanatory as pseudo-code
	if(StringEqual(rel-->6, (+ the topic understood +))) {
		! this will call a routine appropriate to the type of the relation, but I haven't worked out the details yet
	}
];
-).