SWI Prolog does not terminate - prolog

:- use_module(library(clpfd)).
fact(treated=A) :- A in 0..1.
fact(numYears=B) :- B in 0..sup.
fact(numDrugs=C) :- C in 0..sup.
fact(treated2=D) :- D in 0..1.
fact(cParam=E) :- E in 0..4.
is_differentfact(X,X) :- false.
is_differentfact(Element=_,OtherElement=_) :-
dif(Element,OtherElement).
is_fakt([]).
is_fakt([X|Xs]) :-
fact(X),
maplist(is_differentfact(X),Xs),
is_fakt(Xs).
Why does ?- is_fakt(X) return a list of results answers but after a number of results answers it hangs. I don't know why Prolog cannot return all possible values of X.

You ask:
Why does ?- is_fakt(L) ... but after a number of results answers it hangs.
You say a number. That number is 62 times pressing SPACE to get to that moment of looping. Pretty long isn't it? And your program is tiny. How will you ever get the chance to do the same with a bigger program? Don't worry, there is help. But you need to look at the program from a different angle.
In Prolog understanding the very precise execution of a concrete query is next to impossible. You have two different kinds of control flows interleaved plus strange data structures that do not need to be present, but "come in" later ; sometimes. All that opens up a veritable panoply of possible execution traces that are so full of detail, that your mind will overflow — worse: your mind will still pretend you understand everything but effectively you don't. And the bugs have big party time in your program. Those bugs will bite at some point in time in the future, but only on a bug-to-bite basis. That can be very demoralizing. After all, the program is so small, that should be easy to understand (by the standards of imperative languages). But then, Prolog programs tend to be very compact for problems that are very complex in other languages.
Try to step through with a tracer to see what I mean. You will see all kinds of things happening. And most of them are irrelevant.
Fortunately, there are ways to understand Prolog, but here you have to rely on nice properties of the language itself. For localizing reasons for non-termination, the best is to start to consider a failure-slice. You obtain a failure slice from your program by adding goals false into your program. If the resulting program then still does not terminate, we have a reason why also our original program does not terminate.
Think of it: instead of trying to understand your program we do something humans are much better at: Making an educated guess. That guess can go wrong but we can check that easily. In the beginning you will be pretty awful at guessing. Soon you will see that you can do a lot of things systematically. All code that now becomes irrelevant is stike through.
:- use_module(library(clpfd)).
fact(treated=A) :- A in 0..1.
fact(numYears=B) :- B in 0..sup, false.
fact(numDrugs=C) :- C in 0..sup, false.
fact(treated2=D) :- D in 0..1, false.
fact(cParam=E) :- E in 0..4, false.
is_differentfact(X,X) :- false.
is_differentfact(Element=_,OtherElement=_) :-
dif(Element,OtherElement).
is_fakt([]).
is_fakt([X|Xs]) :-
fact(X),
maplist(is_differentfact(X),Xs),
is_fakt(Xs).
What did we gain? We can narrow down the problem much faster:
?- is_fakt(Xs).
Xs = []
; Xs = [treated=_A], _A in 0..1
; loops.
Before continuing, I try to understand what you mean with is_fakt/1. You probably mean: All the facts by their name, and make sure none is repeated. Now we have only the fact named treated, so we can only produce a list of length 1. And then it loops.
You said:
I don't know why Prolog cannot return all possible values of X.
To be picky, that is not true. Prolog did enumerate all possible values of X. But then it did not terminate.
((Some remarks to consider: Do you really want to get that list in that manner? You will get all permutations! With a list of length n you will get n! different answers. For n = 10 that is 3628800. Is this, what you want? Probably not.))
But let us first stick to identify the precise reason for non-termination.
To better identify the reason, lets "turn off" all answers. So we query is_fakt(L), false instead with:
:- use_module(library(clpfd)).
fact(treated=A) :- A in 0..1.
fact(numYears=B) :- B in 0..sup, false.
fact(numDrugs=C) :- C in 0..sup, false.
fact(treated2=D) :- D in 0..1, false.
fact(cParam=E) :- E in 0..4, false.
is_differentfact(X,X) :- false.
is_differentfact(Element=_,OtherElement=_) :-
dif(Element,OtherElement).
is_fakt([]) :- false.
is_fakt([X|Xs]) :-
fact(X),
maplist(is_differentfact(X),Xs), false,
is_fakt(Xs).
That is a minimal failure-slice. So it is the maplist/2 which does not terminate in the first place. Your idea was to ensure that X has a fact-name that is different to the fact-names in Xs. But if Xs is not bound, that will never terminate. Let's try it:
?- maplist(is_differentfact(X),Xs).
Xs = []
; X = (_A=_B), Xs = [_C=_D], dif(_A,_C)
; X = (_A=_B), Xs = [_C=_D,_E=_F], dif(_A,_C), dif(_A,_E)
; X = (_A=_B), Xs = [_C=_D,_E=_F,_G=_H],
dif(_A,_C), dif(_A,_E), dif(_A,_G)
; X = (_A=_B), Xs = [_C=_D,_E=_F,_G=_H,_I=_J],
dif(_A,_C), dif(_A,_E), dif(_A,_G), dif(_A,_I)
; X = (_A=_B), Xs = [_C=_D,_E=_F,_G=_H,_I=_J,_K=_L],
dif(_A,_C), dif(_A,_E), dif(_A,_G), dif(_A,_I), dif(_A,_K)
; ... .
Not so nice to look at... but we can do it better:
?- maplist(is_differentfact(X),Xs), false.
loops.
So it loops. This is the reason for non-termination. To fix the problem we have to do something in the remaining visible part of the failure slice...
For more, look up other explanations tagged failure-slice

Edited version based on the comments of false.
:- use_module(library(clpfd)).
:- use_module(library(lists)).
fact(treated-X) :- X in 0..1.
fact(numYears-X) :- X in 0..sup.
fact(numDrugs-X) :- X in 0..sup.
fact(treated2-X) :- X in 0..1.
fact(cParam-X) :- X in 0..4.
facts(Facts) :-
findall(X,fact(X),Facts).
is_fact2(_, []).
is_fact2(Facts, [X|Xs]) :-
member(X,Facts),
select(X,Facts,Remaining),
is_fact2(Remaining,Xs).
is_fakt(X) :-
facts(Facts),
is_fact2(Facts,X),
keysort(X,X).
This terminates now.

Related

How is it that a clause that requires a ground term works, but that term isn't ground outside of the clause?

I'd like to test whether a term has only one solution.
(Understanding that this might be done in different ways) I've done the following and would like to understand why it doesn't work, if it can be made to work, and if not, what the appropriate implementation would be.
First, I have an "implies" operator (that has seemed to work elsewhere):
:- op(1050,xfy,'==>').
'==>'(A,B) :-·forall(call(A), call(B)).
next I have my singleSolution predicate:
singleSolution(G) :- copy_term(G,G2), (call(G), call(G2)) ==> (G = G2).
Here I'm trying to say: take a term G and make a copy of it, so I can solve them independently. Now if solving both independently implies they are equal, then there must be only one solution.
This works in some simple cases.
BUT.
I have a predicate foo(X,Y,Z) (too large to share) which solves things properly, and for which singleSolution can answer correctly. However, X,Y,Z are not fully ground after singleSolution(foo(X,Y,Z)) is called, even though they would be after directly calling foo(X,Y,Z).
I don't understand that. (As a sanity test: I've verified that I get the same results under swi-prolog and gprolog.)
EDIT: Here is an example of where this fails.
increasing([]).
increasing([_]).
increasing([X,Y|T]) :- X < Y, increasing([Y|T]).
increasingSublist(LL,L) :-·
sublist(L,LL),
length(L, Len),
Len > 1,
increasing(L).
then
| ?- findall(L, singleSolution(increasingSublist([1,2],L)),R).
R = [_]
yes
But we don't know what L is.
This seems to work, but I'm not sure if it's logically sound :)
It uses call_nth/2, a nonstandard but common predicate. It abuses throw to short-circuit the computation. Using bagof/3 instead of findall/3 lets us keep the Goal argument bound (and it will fail where findall/3 would succeed if it finds 0 solutions).
only_once(Goal) :-
catch(bagof(_, only_once_(Goal), _), too_many, fail).
only_once_(Goal) :-
call_nth(Goal, N),
( N > 1
-> throw(too_many)
; true
).
Testing it (on SWI):
?- only_once(member(X, [1])).
X = 1.
?- only_once(member(a, [a, b])).
true.
?- only_once(member(X, [a, b])).
false.
?- only_once(between(1,inf,X)).
false.
Unfortunately, I don't think call_nth/2 is supported in GNU Prolog.
Another possible solution:
single_solution(G) :-
copy_term(G, H),
call(G),
!,
( ground(H)
-> true
; \+ ( call(H), G \= H ) % There is no H different from G
).
p(a).
p(a).
q(b).
q(c).
Examples:
?- single_solution( p(X) ).
X = a.
?- single_solution( q(X) ).
false.
?- single_solution( member(X, [a,a,a]) ).
X = a.
?- single_solution( member(X, [a,b,c]) ).
false.
?- single_solution( repeat ).
true.
?- single_solution( between(1,inf,X) ).
false.
?- single_solution( between(1,inf,5) ).
true.
Here is an another approach I came up with after #gusbro commented that forall/2 doesn't bind variables from the calling goal.
single_solution(G) :-·
% duplicate the goal so we can solve independently
copy_term(G,G2),
% solve the first goal at least / at most once.
G, !,
% can we solve the duplicate differently?
% if so, cut & fail. Otherwise, succeed.
(G2, G2 \= G, !, fail; true).

Non-termination of common reverse/2 implementation, and better solutions?

The following is a standard textbook definition of reverse(X,Y) which is true if the list Y is the reverse of the list X. The code is often used to introduce or illustrate the use of an accumulator.
% recursive definition
step([], L2, L2).
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]).
% convenience property around step/3
reverse(X, Y) :- step(X, Y, []).
The following query works as expcted.
?- reverse([1,2,3], Y).
Y = [3,2,1]
But the following fails after it prompts to search for more solutions after the first one.
?- reverse(X, [1,2,3]).
X = [3,2,1]
Stack limit (0.2Gb) exceeded
Stack sizes: local: 3Kb, global: 0.2Gb, trail: 0Kb
Stack depth: 4,463,497, last-call: 100%, Choice points: 12
...
Questions:
What is the choice point prolog is going back to?
Is this called non-termination? I am not familiar with prolog terminology.
Is there a better way to define reverse(X,Y) such that it is reversible, in the sense that both of the above queries work and terminate?
I have found that using a cut step([], L2, L2):- !. appears to work, but this seems like we've waded into procedural programming and have drifted far away from declarative logic programming. Is this a fair judgement?
1mo, frankly I do not know what kind of choicepoint is responsible. This is a notion far too low level to be of direct relevance. And there are better techniques to understand the problem, in particular failure slices.
2do, the problem here is called (universal) non-termination. But note how you found it: You got an answer and then only when demanding the next answer Prolog looped. This can be even worse, like looping only after the n-th answer. The easiest way to spot all kinds of non-termination is to just add false to the query. If G_0 terminates universally also G_0, false terminates (and fails).
3tio, yes there is. But first, try to understand why your original program looped. The best is to add some falsework into your program. By adding goals false we obtain a failure-slice. And if we find such a slice that already does not terminate then also the original program does not terminate. (No further analysis required!1) Here is the one of relevance:
step([], L2, L2) :- false.
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]), false.
reverse(X, Y) :- step(X, Y, []), false.
?- reverse(X, [1,2,3]), false.
loops.
So we need to understand only that visible part! As promised, there is now not a single choicepoint present.
Just look at the head of step/3! There, only the first argument insists on some specific term, but the second and third do not insist on anything. Therefore the second and third argument cannot influence termination. They are termination neutral. And thus, only the first argument of reverse/2 will influence termination.
To fix this, we need to somehow get the second argument of reverse/2 into a relevant position in step. The simplest way is to add another argument. And, if we are at it, we may realize that both arguments of reverse/2 are of the same length, thus:
step([], L2, L2, []).
step([H1|T1], X, L2, [_|Y]) :- step(T1, X, [H1|L2], Y).
reverse(X, Y) :- step(X, Y, [], Y).
?- reverse(X, [1,2,3]), false.
false.
?- reverse([1,2,3], Y), false.
false.
?- reverse(X,Y).
X = [], Y = []
; X = [_A], Y = [_A]
; X = [_A,_B], Y = [_B,_A]
; X = [_A,_B,_C], Y = [_C,_B,_A]
; ... .
4to, don't believe the tale of the green cut! They are so rare. Most good cuts are placed together with a guard that ensures that the cut is safe. See how your cut wreaked havoc:
?- X = [a], reverse(X,Y).
X = "a", Y = "a". % nice
?- reverse(X,Y), X = [a].
false, unexpected.
?- reverse(L,[]).
L = [].
?- L = [_|_], reverse(L,[]).
loops, unexpected.
So sometimes the program will fail incorrectly, and the looping is still present. Hardly an improvement.
1 Assuming that we use the pure monotonic subset of Prolog
Yes, you have correctly noted that this predicate does not terminate when you pass a variable in the first argument. It also does not terminate if the first argument is a partial list.
The first witness that you reported comes from the fact step([], L2, L2)., which is clearly the base case for your recursion/induction. When you ask the Prolog engine for additional witnesses, it proceeds by trying to do so using the induction rule step([H1|T1], X, L2) :- step(T1, X, [H1|L2]). Note that your implementation here is defined recursively on the first argument, and so this unifies the unbound first argument with [H1|T1], and then makes a recursive call with T1 as the first argument, which then unifies with a fresh [H1|T1], which makes a recursive call... This is the cause of the infinite loop you're observing.
Yes.
Often times with nontermination issues, it's helpful to understand Prolog's execution model. That doesn't necessarily mean we can't come up with a "pure logic" solution, though. In this case, the query doesn't terminate if the first argument is a partial list, so we simply need to ensure that the first argument has a fixed length. What should its length be? Well, since we're reversing a list it should be the same as the other list. Try out this definition instead:
reverse(X, Y) :- same_length(X, Y), step(X, Y, []).
This solves the problem for both of the queries you posed. As an added bonus, it's actually possible to pose the "most general query" and get a sensible infinite sequence of results with this definition:
?- reverse(X, Y).
X = Y, Y = [] ;
X = Y, Y = [_] ;
X = [_A, _B],
Y = [_B, _A] ;
X = [_A, _B, _C],
Y = [_C, _B, _A] ;
X = [_A, _B, _C, _D],
Y = [_D, _C, _B, _A] ;
...
As far as I know, there isn't really a clear way to describe Prolog's cut operator in the language of first order logic. All of the literature I've read on the topic describe it operationally within the context of Prolog's execution model — by this I mean that its semantics are defined in terms of choice points/backtracking rather than propositions and logical connectives. That being said, it's hard to write Prolog code that is fast or has good termination properties without being aware of the execution model, and "practical" Prolog programs often use it for this reason (look up "Prolog red and green cuts"). I think your judgement that the cut is "procedural" is on the right track, but personally I think it's still a valuable tool when used appropriately.
swi-prolog added an extra argument to fix such termination:
?- reverse(L, [1,2,3]).
L = [3,2,1].

Is it possible to write an inconsistent Prolog program using only pure Prolog, cut and `false`?

This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.

Prolog program returns false

I implemented the following power program in Prolog:
puissance(_,0,1).
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
The code does what is supposed to do, but after the right answer it prints "false.". I don't understand why. I am using swi-prolog.
Can do like this instead:
puissance(X,N,P) :-
( N > 0 ->
A is N-1,
puissance(X,A,Z),
P is Z*X
; P = 1 ).
Then it will just print one answer.
(Your code leaves a `choice point' at every recursive call, because you have two disjuncts and no cut. Using if-then-else or a cut somewhere removes those. Then it depends on the interpreter what happens. Sicstus still asks if you want ((to try to find)) more answers.)
Semantic differences
Currently, there are 3 different versions of puissance/3, and I would like to show a significant semantic difference between some of them.
As a test case, I consider the query:
?- puissance(X, Y, Z), false.
What does this query mean? Declaratively, it is clearly equivalent to false. This query is very interesting nevertheless, because it terminates iff puissance/3 terminates universally.
Now, let us try the query on the different variants of the program:
Original definition (from the question):
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Accepted answer:
?- puissance(X, Y, Z), false.
false.
Other answer:
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Obviously, the solution shown in the accepted answer yields a different result, and is worth considering further.
Here is the program again:
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Let us ask something simple first: Which solutions are there at all? This is called the most general query, because its arguments are all fresh variables:
?- puissance(X, Y, Z).
Y = 0,
Z = 1.
The program answers: There is only a single solution: Y=0, Z=1.
That's incorrect (to see this, try the query ?- puissance(0, 1, _) which succeeds, contrary to the same program claiming that Y can only be 0), and a significant difference from the program shown in the question. For comparison, the original program yields:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
ERROR: puissance/3: Arguments are not sufficiently instantiated
That's OK: On backtracking, the program throws an instantiation error to indicate that no further reasoning is possible at this point. Critically though, it does not simply fail!
Improving determinism
So, let us stick to the original program, and consider the query:
?- puissance(1, 1, Z).
Z = 1 ;
false.
We would like to get rid of false, which occurs because the program is not deterministic.
One way to solve this is to use zcompare/3 from library(clpfd). This lets you reify the comparison, and makes the result available for indexing while retaining the predicate's generality.
Here is one possible solution:
puissance(X, N, P) :-
zcompare(C, 0, N),
puissance_(C, X, N, P).
puissance_(=, _, 0, 1).
puissance_(<, X, N, P) :-
A #= N-1,
puissance(X, A, Z),
P #= Z*X.
With this version, we get:
?- puissance(1, 1, Z).
Z = 1.
This is now deterministic, as intended.
Now, let us consider the test case from above with this version:
?- puissance(X, Y, Z), false.
nontermination
Aha! So this query neither throws an instantiation error nor terminates, and is therefore different from all the versions that have hitherto been posted.
Let us consider the most general query with this program:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z,
Y = 1,
Z in inf..sup ;
Y = 2,
X^2#=Z,
Z in 0..sup ;
Y = 3,
_G3136*X#=Z,
X^2#=_G3136,
_G3136 in 0..sup ;
etc.
Aha! So we get a symbolic representation of all integers that satisfy this relation.
That's pretty cool, and I therefore recommend you use CLP(FD) constraints when reasoning over integers in Prolog. This will make your programs more general and also lets you improve their efficiency more easily.
You can add a cut operator (i.e. !) to your solution, meaning prolog should not attempt to backtrack and find any more solutions after the first successful unification that has reached that point. (i.e. you're pruning the solution tree).
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Layman's Explanation:
The reason prolog attempts to see if there are any more solutions, is this:
At the last call to puissance in your recursion, the first puissance clause succeeds since P=1, and you travel all the way back to the top call to perform unification with P with the eventual value that results from that choice.
However, for that last call to puissance, Prolog didn't have a chance to check whether the second puissance clause would also be satisfiable and potentially lead to a different solution, therefore unless you tell it not to check for further solutions (by using a cut on the first clause after it has been successful), it is obligated to go back to that point, and check the second clause too.
Once it does, it sees that the second clause cannot be satisfied because N = 0, and therefore that particular attempt fails.
So the "false" effectively means that prolog checked for other choice points too and couldn't unify P in any other way that would satisfy them, i.e. there are no more valid unifications for P.
And the fact that you're given the choice to look for other solutions in the first place, exactly means that there are still other routes with potentially satisfiable clauses remaining that have not been explored yet.

prolog permutation(?L, ?L1)

I am trying to create a permute(?L, ?L1) predicate.
So that when I execute:
permute([1,2], X).
X = [1,2] ;
X = [2,1];
permute(X, [1,2]).
X = [1,2]
X = [2,1]
If you run the built-in function:
permutation(X, [1,2]).
The stack overflows.
I have tried codes like:
permute1([], []).
permute1([X|Rest], L) :-
permute1(Rest, L1),
select(X, L, L1).
permute2([], []).
permute2(L, [P | P1]) :-
select(P, L, L1),
permute2(L1, P1).
generator(L, L1):-
findall(X,permutation(L,X),L1).
but none work.
I appreciate the help beforehand.
The problem with permutation/2 is that it does not terminate as good as it could. So, first, we need to understand what we can expect from a Prolog predicate's termination properties. Note that we can do these considerations without looking at the concrete definition!
Set of solutions
First, start to consider what set of solutions queries possess. If that set is finite, then Prolog might terminate. If it is infinite, and we would have to enumerate all solutions, then we cannot expect Prolog to terminate. In your example, consider
permute(L,[]). Here, the set is finite, it would therefore be nice, if the predicate would terminate.
permute([X],L). Here, the set is infinite.
But are we really interested in seeing all solutions? Like X = 1, L = [1] and many, many more? In fact, X might be any term, so we might relax (or generalize) what we expect from Prolog: Instead of concrete solutions, we might be happy with answer substitutions that also contain variables. In fact, L = [X] describes all infinitely many solutions with a single answer substitution.
Answers
In case the set of solutions is infinite, we will try to figure out if that set can be described with finitely many answers. However, if only infinitely many answers are able to represent the set of solutions, a query must not terminate. Consider:
permute([a,b|L],[c,d|M]). Here, we need infinitely many answers. Like
L = [c,d], M = [a,b] ; L = [c,d,X1], M = [a,b,X1] etc. If the predicate would terminate in such a situation, some solutions would be left out.
So after these considerations we now know where a predicate might terminate, and where it must loop. In our case, permute/2 must loop iff both arguments are partial lists.
To put it in another direction, the predicate (ideally) terminates, if the length of one of the lists is known.
Note that for permute/2, both lists are of same length, thus:
same_length([], []).
same_length([_|Xs], [_|Ys]) :-
same_length(Xs, Ys).
permute(Xs, Ys) :-
same_length(Xs, Ys), % redundant goal
permutation(Xs, Ys).
Instead of same_length/2 you might write maplist(\_^_^true,Xs, Ys) using library(lambda).
You could just have a wrapper around permutation:
permute(X, L) :-
( nonvar(L) ->
permutation(X, L)
;
permutation(L, X)
).
Another method is to constrain the length of the lists to be the same (assuming at least one list is instantiated):
permute(L, P) :-
length(L, N),
length(P, N), !,
permutation(L, P).

Resources