i’m still unclear on when i need to use (exhaust) and when i can just use a multiquery. I’ve just sort of shambled on, trying a multiquery first and then adding the (exhaust) in the cases where it doesn’t work.
these are from the manual and seem functionally identical to me.
(program entry point)
*(fruit $Obj)
$Obj is a fruit.
(colour $Obj)
We found a fruit that is also a colour!
(program entry point)
(exhaust) {
*($X is one of [#door #foot #apple #pencil])
(line)
Checking (the $X).
(fruit $X)
Yes, it's a fruit!
}
the manual seems to imply that the (exhaust) version is simply more thorough? but isn’t the point of a multiquery to try each branch of the search tree anyway?
Multiquery alone will backtrack on fail only, so the first example will find the first fruit that also happens to be a color and then move on. Add (color #banana) to test it, it won’t find the #banana.
Multiquery in an (exhaust) block will backtrack for everything; it behaves as if an invisible (fail) is appended to the end of the block. In fact the manual says,
(exhaust) statement
and
{ statement (fail) (or) }
are equivalent.
Test it by putting all four lines in your example in an (exhaust) block and also add (color #banana). Now it will find both the orange and the banana.
In other words, use a multi-query if you only care about finding a solution, and use (exhaust) if you want to iterate over every solution.
If you’re used to Inform, sometimes you want “let the item be a random thing held by the player”, and sometimes you want “repeat with the item running through things held by the player”.
My favorite rule from the library is (split $ anywhere into $ and $). See if you can figure out what it does and how it does that. One needs to grok choice points, backtracking, and multi query concepts(and unification of partial lists added for good measure) to understand that rule completely.
(split [$First $Second | $Tail] anywhere into [$First] and [$Second | $Tail])
(split [$First | $More] anywhere into [$First | $Left] and $Right)
*(split $More anywhere into $Left and $Right)
If following that rule causes a headache, here is one that uses the same concepts(sans partial lists), but might be easier to understand what and how:
(repeat ($N > 0))
(repeat $N)
($N minus 1 into $Remaining)
*(repeat $Remaining)
Oh, I see. You’re supposed to call this with an (exhaust), not with a normal multi-query, so that the first rule succeeding doesn’t cut it off? That makes more sense!