假设我有一个列表L1 = [1,2,3],我想写一个谓词,它可以找到该列表的所有排列,即
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
注意:我知道permutation(L1, L2).
确实可以做到这一点,但是我想写一个自己的谓词来做练习。
我是一名序言新秀,所以我认为当两个列表L1和L2相互排列时,让我们先做一个谓词,返回true
。要求是:
所以我想到了这个:
permute(L1,L2):-
forall(member(X,L1), member(X,L2)), % every element that is a member in L1 has to be a member in L2
length(L1,A), % the length of the list L1 is A
length(L2,A). % AND the length of the list L2 is A
因此,当我查询permute([1,2,3], [1,3,2]).
时,确实得到了预期的true
,并且permute([1,2,3], [1,3]).
和permute([1,2,3], [1,3,4]).
都给出了false。因此,我的谓词可以查看2个列表是否彼此置换。
但是,如果我问:permute([1,2,3], A).
,我希望能够看到所有有效的A,即[1,2,3]的所有排列。相反,我得到了无限的变量。
像A = [_942, _948, _954].
为什么会这样,为什么我不能浏览所有可能的列表A?有没有简单的方法可以修改我的代码以实现这一目标?
答案 0 :(得分:2)
首先,您的两点定义是错误的。根据它,permute( [1,1,2], [1,2,2])
应该保持(并且确实如此)。
“简单” 方法是使用select/3
,
select( [A|B], X):- select(A, X, Y), select(B, Y).
select( [], []).
它起作用,但仅在一个方向上起作用。即使添加(简单)same_length
也无济于事:
permute( A, B):- same_length( A, B), select( B, A).
same_length( A, B):- length(A, N), length(B, N). % wrong
% permute( [1,2,3], X). % OK
% permute( X, [1,2,3]). % doesn't terminate after the last solution
不,same_length/2
的定义必须仔细,
same_length( [], []).
same_length( [_|A], [_|B]):- same_length(A, B).
然后 permute
在两个方向都可以。