I am struggling to find a way to use transactions to throw away side effect data from the failed choicepoints in a generator predicate. Here’s an example:
Let’s say I have multiple alternatives for a predicate called noun/3
. I want to backtrack over these until I find the right one. Unfortunately, each instance of noun/3 asserts a term. I only want to keep the asserts for proofs that succeed and throw away the others. Below is an example.
The problem is that, since I am calling the noun/3 generator inside the transaction/1 predicate, Prolog only does a “redo” on the generator term, and so the transaction doesn’t rollback, it just keeps collecting changes from the (failed) backtracking.
I think I’m looking for a way to transact each choicepoint generated by the predicate passed to transaction/1 independently, rolling back all data done by a choice point on redo (as opposed to the current transaction/1 predicate that puts them all in a single transaction).
…or some other way of doing this. Unfortunately changing the noun predicates to not side effect is a large rewrite…
findDogInstance(ID) :-
transaction((
noun(dog, ID, Kind),
Kind \== concept
)).
noun(dog, ID, concept) :-
gensym(dog, ID),
assert(test(ID, is, dog, concept)).
noun(dog, ID, instance) :-
gensym(dog, ID),
assert(test(ID, is, dog, instance)).
?- findDogInstance(X).
X = dog2.
?- test(X, Y, Z, A).
% I don't want this one since it wasn't in the successful proof...
X = dog1,
Y = (is),
Z = dog,
A = concept ;
% I do want this one
X = dog2,
Y = (is),
Z = dog,
A = instance.
~~