我正在尝试编写谓词permutation/2
,以便当且仅当两个参数都是列表时才是真的,一个是另一个的排列。为此,我编写了两个辅助谓词delete/3
和insert/3
。第一个是真的,当且仅当第三个参数是第二个参数时,两个列表,第一个参数中第一个参数的实例被删除。当且仅当第三个参数等于插入第一个参数(元素)的第二个参数时,第二个为真。
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.
我的想法是查询
?- insert(A,B,X).
对于给定的A,B应返回实例化X的所有方式,使其等于列表B,并在某处添加元素A.但是,它没有这样做:
?- insert(3,[1,2],X).
X = [1, 2, 3] ;
X = [1, 3, 2] ;
ERROR: Out of global stack
我认为这是因为我定义谓词的方式,检查第三个参数中的列表减去第二个参数中列表的每个元素是否等于仅包含第一个参数的列表,而不是建设性地定义它,但是我很难以另一种方式解决这个问题。然后,置换谓词应检查其第二个参数中的列表是否是递归的置换,方法是检查P是否是随机插入头部的第一个列表尾部的置换。感谢帮助!
答案 0 :(得分:2)
insert/3
和delete/3
都是相同的谓词,在教科书中可以找到select/3
。它也在标准库中,例如在SWI-Prolog中,您可以找到select/3
。您可以使用它来插入或删除,只需根据需要更改列表的位置。
删除" b"来自" abc":
?- select(b, [a,b,c], X).
X = [a, c] ;
false.
插入" b"在" ac"在任何位置:
?- select(b, X, [a,c]).
X = [b, a, c] ;
X = [a, b, c] ;
X = [a, c, b] ;
false.
它的定义与您定义delete/3
完全相同,如果您在SWI-Prolog中看到lists.pl的源代码,它是开源的,您将会看到它。
select(X, [X|Tail], Tail).
select(Elem, [Head|Tail], [Head|Rest]) :-
select(Elem, Tail, Rest).
但现在你可以像你描述的那样定义排列。因为我在相同的源文件lists.pl中也找到了这个,我只是在这里复制源代码,因为它是开源的,所以没关系:
perm([], []).
perm(List, [First|Perm]) :-
select(First, List, Rest),
perm(Rest, Perm).
我使用lists:perm
,因为它是"私有"但它不是私有的,只是没有出口:
?- 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.
我只有一条消息,它是:阅读教科书并阅读来源,因为它可以帮助您更快地学习。