Reputation: 2075
The essential question: how can I assign to an instance variable when a predicate fails?
I have two predicate "functions" (probably wrong terminology). The first predicate calls the second predicate with a new instantiation variable (unassigned). I assign a value to the new variable in the second predicate. However, the second predicate fails. The way I am implementing it, since the predicate fails, the new variable is still unassigned after returning to the first predicate.
func(X, Y) :-
func2(X, NewX);
write(NewX).
func2(X, NewX) :-
NewX is X+1, false.
This prints:
| ?- func(1,1).
_283
However, if the second predicate returns true like so,
func(X, Y) :-
func2(X, NewX),
write(NewX).
func2(X, NewX) :-
NewX is X+1.
Then it prints:
| ?- func(1,1).
2
yes
How can I assign an instance when a predicate fails?
Upvotes: 1
Views: 1037
Reputation: 40768
In Prolog, when a predicate call fails, all variable bindings that were created after the call are undone on backtracking. Consequently, there is no way to "fail and unify" in pure Prolog.
To solve your issue in pure Prolog, declaratively describe the cases that hold.
For example, in your case, you obviously have 2 possible cases:
NewX
is equal to X + 1
So, in Prolog, this could read:
integer_successor(X0, X, true) :- X #= X0 + 1.
integer_successor(X0, X, false) :- X #\= X0 + 1.
Given these definitions, you can now use:
integer_successor(X, NewX, Truth)
and then use Truth
to distinguish the cases.
For example:
other_pred(true) :- ...
other_pred(false) :- ...
This lets you describe the different cases by pattern matching, and retains logical-purity and generality of your code: You can use this as a true relation, in all directions, including for the most general query where all arguments are free variables.
Upvotes: 1