# Looping through relations

I’ve wanted this for a long while: a reasonably fast and efficient way to loop through relations.

``````lab is a room.

foo relates various numbers to various texts.
the verb to boop means the foo relation.
booping is a relation of numbers to texts variable.
booping is initially the foo relation.

4 boops "x".
5 boops "x".
5 boops "z".
6 boops "b".
4 boops "b".

when play begins:
say "Keys (left hand side): ";
repeat for n in keys of booping begin;
say "[n] ";
end repeat;
say ".";
say "Values (right hand side): ";
repeat for t in values of booping begin;
say "[t] ";
end repeat;
say ".";
say "Both!";
repeat for x and y in booping begin;
say "[x] boops [y].";
end repeat;
``````

would yield:

``````Keys (left hand side): 5 4 5 4 6 .
Values (right hand side): z b x x b .
Both!
5 boops z.
4 boops b.
5 boops x.
4 boops x.
6 boops b.
``````

For the current dev version, what’s expected to be 11.0, sorry. I’ll make an extension later; I just thought I’d share it while it’s hot.

``````to repeat for/with/-- (y - nonexisting L variable) running/-- through/in values of (r - relation of values of kind K to values of kind L) begin -- end loop: (-
if (PVField({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KindConformsTo_POINTER_VALUE_TY({-strong-kind:L})) BlkValueCopy({-by-reference:y}, PVField({-by-reference:r}, {-my:1} + 2));
else {-by-reference:y} =  PVField({-by-reference:r}, {-my:1} + 2);
if (1) {-block}
-)

to repeat for/with/-- (x - nonexisting K variable) running/-- through/in keys of (r - relation of values of kind K to values of kind L) begin -- end loop: (-
for ( {-my:0} = PVField({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) : {-my:0} >= 0 : {-my:0}--, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (PVField({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KindConformsTo_POINTER_VALUE_TY({-strong-kind:K})) BlkValueCopy({-by-reference:x}, PVField({-by-reference:r}, {-my:1} + 1));
else {-by-reference:x} =  PVField({-by-reference:r}, {-my:1} + 1);
if (1) {-block}
-)

to repeat for/with/-- (x - nonexisting K variable) and (y - nonexisting L variable) running/-- through/in (r - relation of values of kind K to values of kind L) begin -- end loop: \
(-
for ( {-my:0} = PVField({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) : {-my:0} >= 0 : {-my:0}--, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (PVField({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KindConformsTo_POINTER_VALUE_TY({-strong-kind:K})) BlkValueCopy({-by-reference:x}, PVField({-by-reference:r}, {-my:1} + 1));
else {-by-reference:x} =  PVField({-by-reference:r}, {-my:1} + 1);
if (KindConformsTo_POINTER_VALUE_TY({-strong-kind:L})) BlkValueCopy({-by-reference:y}, PVField({-by-reference:r}, {-my:1} + 2));
else {-by-reference:y} =  PVField({-by-reference:r}, {-my:1} + 2);
if (1) {-block}
-)
``````

(As you can see, insertion order isn’t preserved.)

4 Likes

Very slick, Zed.

The first two versions can be done indirectly with existing functionality:

``````When play begins:
repeat with M running through list of numbers that booping relates:
say "[M]."

When play begins:
repeat with N running through list of texts to which booping relates:
say "[N]."
``````

but the third is something new under the sun, and they’re all handy!

The idea can be backported to 6M62 with:

6M62 Backport Phrases
``````To repeat for/with/-- (x - nonexisting K variable) running/-- through/in keys of (r - relation of values of kind K to values of kind L) begin -- end loop:
(-
for ({-my:0} = BlkValueRead({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) :
{-my:0} >= 0 : {-my:0}--, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (BlkValueRead({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KOVIsBlockValue({-strong-kind:K}))
else
{-by-reference:x} =  BlkValueRead({-by-reference:r}, {-my:1} + 1);
if (1) {-block}
}
}
-).

To repeat for/with/-- (y - nonexisting L variable) running/-- through/in values of (r - relation of values of kind K to values of kind L) begin -- end loop:
(-
for ({-my:0} = BlkValueRead({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) :
{-my:0} >= 0 : {-my:0}--, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (BlkValueRead({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KOVIsBlockValue({-strong-kind:K}))
else
{-by-reference:y} =  BlkValueRead({-by-reference:r}, {-my:1} + 2);
if (1) {-block}
}
}
-).

To repeat for/with/-- (x - nonexisting K variable) and (y - nonexisting L variable) running/-- through/in (r - relation of values of kind K to values of kind L) begin -- end loop:
(-
for ({-my:0} = BlkValueRead({-by-reference:r}, RRV_STORAGE), {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) :
{-my:0} >= 0 : {-my:0}--, {-my:1} = RRV_DATA_BASE + (3 * {-my:0}) ) {
if (BlkValueRead({-by-reference:r}, {-my:1}) & RRF_USED) {
if (KOVIsBlockValue({-strong-kind:K}))
else
{-by-reference:x} =  BlkValueRead({-by-reference:r}, {-my:1} + 1);
if (KOVIsBlockValue({-strong-kind:K}))
else
{-by-reference:y} =  BlkValueRead({-by-reference:r}, {-my:1} + 2);
if (1) {-block}
}
}
-).
``````

I’m not sure that will work in 10.1, but surely something like it can do the trick.

There might be certain bugs to work out for unusual kinds of relations. (I’m not remembering the details, but as I recall the data structures for some of them vary from this format.)

2 Likes

The first two build a list. That’s an expensive operation and it’s a waste if all you want it for is to loop through it once. I did say

a reasonably fast and efficient way to loop through relations

1 Like

I don’t even know what that’s for, but it kind of reads like poetry.

in keys of booping begin
the sad sweet songs of end repeat…

1 Like
3 Likes

That is fricking brilliant. Of course Sarah wrote that. You’re amazing, @malacostraca. And the whole idea is fricking brilliant. Why isn’t this a thing that happens every year? Why isn’t there a forum section for it so it can happen all the time?

6 Likes

Aww, thank you! I am proud of that one. It might be the best thing I’ll ever write.

3 Likes

Those actually have different results. Those phrases uniqify the lists, so, with the example above would yield {5, 4, 6} and {“z”, “b”, “x”}.

Good point!