我正在尝试创建一个permute(?L,?L1)谓词。
这样当我执行时:
permute([1,2], X).
X = [1,2] ;
X = [2,1];
permute(X, [1,2]).
X = [1,2]
X = [2,1]
如果您运行内置功能:
permutation(X, [1,2]).
堆栈溢出。
我尝试了以下代码:
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).
但没有工作。 我事先感谢你的帮助。
答案 0 :(得分:2)
permutation/2
的问题在于它没有尽可能好地终止。因此,首先,我们需要了解Prolog谓词的终止属性我们可以期待什么。请注意,我们可以在不查看具体定义的情况下进行这些考虑!
首先,开始考虑查询具有哪些解决方案。如果该集合是有限的,则Prolog might
终止。如果它是无限的,我们将不得不枚举所有解决方案,那么我们不能指望Prolog终止。在您的示例中,请考虑
permute(L,[])
。在这里,集合是有限的,因此如果谓词将终止,那将是很好的。
permute([X],L)
。这里的集合是无限的。
但我们真的对看到所有解决方案感兴趣吗?像X = 1, L = [1]
和更多,还有更多?事实上,X
可能是任何术语,因此我们可以放松(或概括)我们对Prolog的期望:我们可能会对包含变量的答案替换感到满意,而不是具体的解决方案。 。实际上,L = [X]
描述了所有无限多个解决方案,只有一个答案替换。
如果解决方案集是无限的,我们将尝试确定是否可以用有限多个答案来描述该集合。但是,如果只有无限多个答案能够代表解决方案集,则查询不得终止。考虑:
permute([a,b|L],[c,d|M]).
在这里,我们需要无限多的答案。喜欢
L = [c,d], M = [a,b] ; L = [c,d,X1], M = [a,b,X1]
等。如果谓词在这种情况下终止,则会遗漏一些解决方案。
因此,经过这些考虑,我们现在知道谓词可能终止的位置,以及必须循环的位置。在我们的情况下,permute/2
必须循环,如果两个参数都是部分列表。
如果其中一个列表的长度已知,则将谓词(理想情况下)置于另一个方向上。
请注意,对于permute/2
,两个列表的长度相同,因此:
same_length([], []).
same_length([_|Xs], [_|Ys]) :-
same_length(Xs, Ys).
permute(Xs, Ys) :-
same_length(Xs, Ys), % redundant goal
permutation(Xs, Ys).
您可以使用library(lambda)
撰写same_length/2
,而不是maplist(\_^_^true,Xs, Ys)
。
答案 1 :(得分:1)
你可以在permutation
附近找一个包装器:
permute(X, L) :-
( nonvar(L) ->
permutation(X, L)
;
permutation(L, X)
).
答案 2 :(得分:1)
另一种方法是将列表的长度限制为相同(假设至少有一个列表被实例化):
permute(L, P) :-
length(L, N),
length(P, N), !,
permutation(L, P).