Prolog return results
-
06-03-2021 - |
質問
For homework, so nothing explicit, please:
Is there a way to get Prolog to return only the first Goal found by the program while ignoring the other Goals that are found?
For illustrative purposes, given the program:
permutation([X|Xs],Zs):-permutation(Xs,Ys), insert(X,Ys,Zs).
permutation([],[]).
Is there a way to make the program only return the first permutation as its only solution? In the following case:
| ?- permutation([1,2,3],X).
X = [1,2,3] ? ;
X = [1,3,2] ? ;
X = [2,1,3] ? ;
X = [2,3,1] ? ;
X = [3,1,2] ? ;
X = [3,2,1] ? ;
no
Can we just have
X = [1,2,3] ?;
no
as the solution?
解決
The cut it's the control you are looking for. Place it where you need to commit to a solution (here on toplevel, I guess). There is also the builtin once/1, that allows to restrict the scope of the commit 'locally' (useful for instance inside a conjunction inlined in a findall/3).
他のヒント
Prolog sets choicepoints whenever an alternative branch in the search tree is possible. In order to avoid backtracking to a choicepoint and exploring such alternatives, you have to add a cut (!/0
).
You have to check where in your program the choicepoint is set, and add the cut after that call.
The best way to stick to the first solution is once/1
since this keeps the effects as local as possible. Using !/0
often has already unintended effects, since the scope of !/0
is larger. Let's take a very simple example: The query ( X = 1 ; X = 2 ; X = 3 )
in
p(X) :- ( X = 1 ; X = 2 ; X = 3 ).
p(4).
Using once/1
we get:
p1(X) :- once( ( X = 1 ; X = 2 ; X = 3 ) ).
p1(4).
?- p1(X).
X = 1 ;
X = 4.
Using !
, we get only a single answer:
p2(X) :- ( X = 1 ; X = 2 ; X = 3 ), !.
p2(4).
?- p2(X).
X = 1.
Often this is not intended.
But there is a more general problem with committing to the first solution.
?- p1(2).
true.
?- dif(X,1),p1(X).
X = 2 ;
X = 4.
So, also 2 is now a first solution? It is for such reasons that committing must be used quite cautiously. A predicate that shows similar behavior as p1/1
lacks steadfastness. Such a predicate cannot be understood as a relation since it changes its meaning depending on the actual query.