问题
I am trying to write a predicate permutation/2
so that it is true if and only if both arguments are list, one a permutation of the other. To do this, I've written the two helper predicates delete/3
and insert/3
. The first is true if and only if the third argument is the second argument, both lists, with the first instance of the element in the first argument removed. The second is true if and only if the third argument equals the second argument with the first argument (element) inserted.
delete(X,[X|T],T). % Base case, element equals head.
delete(X,[A|B],[A|C]) :- delete(X,B,C). % Else, repeat for the tail.
insert(X,[],[X]). % Base case.
insert(X,[H|T],B) :- delete(H,B,U), insert(X,T,U). % Delete all elements from B.
permutation([],[]). % Base case.
permutation([H|T],P) :- permutation(Q,T), insert(H,Q,P). % P a permutation of T, H inserted.
My idea is that the query
?- insert(A,B,X).
For given A, B should return all ways of instantiating X so that it equals the list B with the element A added somewhere. However, it does not do this:
?- insert(3,[1,2],X).
X = [1, 2, 3] ;
X = [1, 3, 2] ;
ERROR: Out of global stack
I think this is because of the way I defined the predicate, checking if the list in the third argument minus every element of the list in the second argument equals the list containing only the first argument, rather than defining it constructively, but I am having a hard time solving this problem another way. The permutation predicate should then check if the list in its second argument is a permutation recursively, by checking if P is a permutation of the tail of the first list with the head randomly inserted. Help is appreciated!
回答1:
Both insert/3
and delete/3
is the same predicate and it is found in textbooks as select/3
. It is also in standard library, for example in SWI-Prolog you can find it as select/3
. You can use it to insert or delete, just change the position of the list as necessary.
Delete "b" from "abc":
?- select(b, [a,b,c], X).
X = [a, c] ;
false.
Insert "b" in "ac" in any position:
?- select(b, X, [a,c]).
X = [b, a, c] ;
X = [a, b, c] ;
X = [a, c, b] ;
false.
It is defined exactly as you did define delete/3
, if you see the source of lists.pl in SWI-Prolog which is open source you will see it.
select(X, [X|Tail], Tail).
select(Elem, [Head|Tail], [Head|Rest]) :-
select(Elem, Tail, Rest).
But now you can define permutation just like you described. Because I find also this in the same source file lists.pl I just copy the source here, and it is ok because it is open source:
perm([], []).
perm(List, [First|Perm]) :-
select(First, List, Rest),
perm(Rest, Perm).
I use lists:perm
because it is "private" but it is not private it is just not exported:
?- lists:perm([a,b,c], P).
P = [a, b, c] ;
P = [a, c, b] ;
P = [b, a, c] ;
P = [b, c, a] ;
P = [c, a, b] ;
P = [c, b, a] ;
false.
?- lists:perm([a,b,c], [b,a,c]).
true ;
false.
I have just one message and it is: read the textbook and read the source because it helps you learn much faster.
来源:https://stackoverflow.com/questions/43094844/prolog-permutation-predicate-using-insertion-of-elements