comparing text substitutions

I’d like to be able to compare two text strings and see if they print the same thing, like this:

[code]
Use the serial comma.

Language Lab is a room.

A thing has some text called the plain name. The plain name of a thing is usually “[the printed name of item described]”.
A thing has some text called the florid name. The florid name of a thing is usually “[the printed name of item described]”.

Florid mode is a truth state that varies. Florid mode is false.

Floridifying is an action applying to nothing. Understand “florid” as floridifying.

Check floridifying when florid mode is true: say “We’re already in florid mode.” instead.

Carry out floridifying:
now florid mode is true.

Report floridifying:
repeat with item running through things:
if the florid name of the item is not the plain name of the item:
say “We will now refer to [the plain name of the item] as [the florid name of the item].”

The unremarkable potato is in Language Lab. The beet is in Language Lab. The florid name of the beet is “remarkable crimson-hued chenopodiaceous root”. The incredibly boring rock is in Language Lab. The plain name of the incredibly boring rock is “rock”. The florid name of the incredibly boring rock is “rock”.

For printing the name of a thing:
if florid mode is true:
say “[florid name of the item described]”;
otherwise:
say “[plain name of the item described]”.

Test me with “florid”.[/code]

But as the test shows, “florid name of the item is not the plain name of the item” only comes out true when the names are literal strings (as for the rock), not when they include text substitutions – even if they’re the same text substitution (as for the potato and yourself).

Is there a workaround for this other than casting everything into indexed text and comparing it? Would the indexed text comparisons be prohibitively computationally expensive if I had to do them, say, ten times a turn? Ten times a turn combined with a lot of crazy list operations?

(The code I’ve posted has a lot of other problems – the articles don’t work, for one – but I’m actually shooting for another application where the text comparison problem is the one that really matters.)

Nope. You’re stuck with indexed text as far as I’m aware. Doing it ten times a turn would be… I’m not sure, honestly. You’d have to test it on a slow interpreter.

It would be nice if the I7 compiler could unify identical functions, like it does with identical strings. There can be a lot of redundancy in its generated code.

In general, you can test whether the same function is being called for two instances of text substitution by doing this:

To decide what number is the comparable form of (O - a sayable value): (- {O} -)

You could use this for your case like this:

if the comparable form of the florid name of the item is not the comparable form of the plain name of the item

…but only if, as zarf suggested, the two were actually calling the same function. Unfortunately, they aren’t: the code is generated such that the default value of the plain name is one function, while the default value of the florid name is another.

–Erik

Simply testing “if A is B” will work for two texts if they are compiled as the same low-level function. You don’t need to go through the comparable form thing.

I suppose that’s the upside of redundancy.

The Swedish translation of Inform does this kind of thing to match player’s commands with the printed names of objects (this is convenient due to the inflection of Swedish nouns). If objects have long names, it does slow performance down on slow processors and on slow interpreters. (On the interpreter that the IDE uses the slow-down is soon noticeable even on up-to-date computer processors.)

Ooh Felix, that sounds interesting to me even independent of this particular problem. Can you point me to some code about how you do that?

Sure. The relevant code is sprinkled bits and pieces throughout “Swedish”, but I think I can get the nontrivial parts together.

Thanks so much!

I think this is it. (I find that I’m happy I made extensive comments on the code, while I understood it!)
It’s pretty much bound not to be the most efficient way of doing the thing, so I’d be grateful for any suggestions for improvements.

[spoiler][code]

[We want the game to understand the printed name of an object as that object, since normally the printed name of an object will contain the definite inflection of the object’s name. It’s probably good if this can be overriden, though.]

An object can be understood by its printed name or not understood by its printed name.
An object is usually understood by its printed name.
The understood by its printed name property translates into I6 as “short_name_understood”.

Include (-
Attribute short_name_understood; ! flags objects to be understood by their printed name
-) after “Template Attributes” in “Definitions.i6t”

[These variables are used only in the phrases to decide if the printed name is understood and to decide if the indexed name is understood, called by the custom I6 routine LanguageRefers in the process of determining the reference of input nouns. The The LR-formal-supposition holds the object whose printed name we are matching against the input noun. The LR-material-supposition holds the input noun we are trying to match against. (In scholastic logic, the formal supposition of a word is what the word normally refers to in “use”; the material supposition is the word itself in “mention”.)]

The LR-formal-supposition is an object that varies. The LR-formal-supposition variable translates into I6 as “LR_object”.
The LR-material-supposition is indexed text that varies. The LR-material-supposition variable translates into I6 as “parameter_object”.

[These phrases are called by the I6 LanguageRefers() routine. They match the printed name of a given object in scope (the LR-formal-supposition – LR_object in I6) against a would-be noun in the player’s command (the LR-material-supposition, which is yet another I7 name for the I6 parameter_object variable).]

To decide if the printed name is understood:
let numbawords be the number of words in the printed name of LR-formal-supposition;
repeat with wordnumba running from 1 to numbawords:
if word number wordnumba in the printed name of the LR-formal-supposition exactly matches the text LR-material-supposition, case insensitively:
decide yes.

[We define a LanguageRefers routine to make sure that the Swedish translation understands the short_name (printed name) of objects, as the author normally will give the definite forms of object names there. This mirrors the standard I6 Refers routine but adds an else block that tries to match the input word (the value of parameter_object) against each word in the printed name of a given object in scope (the value of LR_object), using both the definite and the indefinite forms of the printed name (that’s why we change the indef_mode global at the end of the routine). The routine relies on an I7 phrase matching indexed texts against each other.]

Include (-
Global LR_object = nothing;

[ LanguageRefers obj wnum wd k po spec_mode;
if (obj == 0) rfalse;

!# if parser_inflection is set to a routine, run it
k = wn; wn = wnum; wd = NextWordStopped(); wn = k;
if (parser_inflection >= 256) {
k = indirect(parser_inflection, obj, wd);
if (k >= 0) return k;
}

!# if parser_inflection is set to a property (by default it’s set to the name property), look in it for our word
k = WordInProperty(wd, obj, parser_inflection);
if (k>0) rtrue;

!# and if we don’t find the word we look for in that property, check the object’s short_name (i.e. the I7 printed name)
else if (obj has short_name_understood) {
LR_object = obj; po = parameter_object; spec_mode = indef_mode;
parameter_object = INDEXED_TEXT_TY_Create();
INDEXED_TEXT_TY_Cast(wnum*100+1, SNIPPET_TY, parameter_object);
k = (+ whether or not the printed name is understood +);
if (k>0) {
parameter_object = po;
rtrue;
}
if (indef_mode == false) indef_mode = true;
else indef_mode = false;
k = (+ whether or not the printed name is understood +);
indef_mode = spec_mode; parameter_object = po;
if (k>0) rtrue;
else rfalse;
}

else rfalse;
];
-) before “Refers” in “Parser.i6t”.

[/code][/spoiler]

We need to rewrite the indexed text implementation. It could be a whole lot smarter.

Felix, that looks great, although I have to say I don’t read I6 so I don’t understand what’s going in the last part where the work is going on. And trying to figure it out in terms of Ron’s I7 implementation of the parser is just giving me a massive headache…

In this case, even with your code the beet still won’t respond to “get root” (in florid mode) because its printed name remains “beet” even though the outcome of the rule for printing its name is something different. Ideally I’d like to be able to get the outcome of the rule for printing an object ("[beet]" rather than “[printed name of the beet]”) and match the player’s command to that.

Of course this isn’t meant as a criticism, it’s just that I’m well above my pay grade here.

I’d hoped that I’d be able to hack something into one of Ron’s parsing routines, but it’s pretty clear to me that at the parts I was looking at the command had already been broken down into dictionary words, so anything not in the dictionary is lost. Which means if I want to recover the text that was typed and try to convert it into an object, I need some sort of I6 like yours. I think. (That is, in order to get the beet to respond to “root” in florid mode. If I use indexed text it’s not too bad to change the example in my original post; all I have to do is write:

unless "[florid name of item]" exactly matches the text "[plain name of item]":

in place of the condition I had.)

One thing you could do if it is speed you’re after is define a truth state for every item with true as the default then change it to false when the descriptions are changed. This way, the loops only need to check the truth state rather than compare the texts.