我想要做的是生成给定列表中的所有元素组合。例如:从[a,b,c],我可能想要:
[]
[a]
[b]
[c]
[a,a]
[a,b]
[a,c]
[b,a]
...
等等。也许有一个神奇的prolog单行程就可以做到这一点。如果是这样,我很乐意听到它。
然而,我的问题不是解决这个特殊问题,更多的是要求有人解释Prolog搜索算法的一些细微之处。
所以这就是我首先解决上述问题的方法:
members([], _).
members([X|Xs], List) :-
member(X,List),
members(Xs, List).
这很有效,但会返回所有可能的结果,而不是很好的顺序:
[]
[a]
[a,a]
[a,a,a]
好的,这没问题。我真的只想要所有组合达到一定的长度。所以我决定先得到具有特定长度的那些:
membersWithLength(Members, List, Bound) :-
L = Bound,
length(Members, L), members(Members, List).
这很有用,例如长度为2:
[a,a]
[a,b]
[a,c]
...
等等。现在我尝试使用clpfd来利用上面的函数来使所有列表达到一定的长度出错了:
:- use_module(library(clpfd)).
membersLessThan(Members, List, Bound) :-
L in 0..Bound, % I also tried L #=< Bound
membersWithLength(Members, List, L).
有点作品。找到正确的结果(长度小于Bound的列表)。 但在找到它们之后,它会不断循环搜索更多结果。例如。长度为2:
[]
[a]
[b]
[c]
[a,a]
[a,b]
...
[c,c]
Hangs looking for more solutions.
我想这是我问题的核心。有人可以解释为什么(根据跟踪)prolog继续检查越来越大的列表作为可能的解决方案,即使它们都注定要失败?有人可以告诉我,是否有办法帮助prolog避免这种注定的旅程?
我最终使用以下代码来解决问题,但我很失望,我无法弄清楚如何使用clpfd的整数约束来约束列表的大小。
membersLessThan_(Members, List, Bound) :-
numlist(0,Bound,ZeroToBound),
member(L, ZeroToBound),
membersWithLength(Members, List, L).
以下是SWISH的所有相关代码:http://swish.swi-prolog.org/p/allcombos.pl
答案 0 :(得分:0)
如果您想要列举所有答案,可以使用原始的成员实现:
length(L, _), members(L, [a,b,c]).
给你答案:
L = [] ;
L = [a] ;
L = [b] ;
L = [c] ;
L = [a, a] ;
L = [a, b] ;
L = [a, c] ;
L = [b, a] ;
L = [b, b] ;
L = [b, c] ;
L = [c, a] ;
L = [c, b] ;
L = [c, c] ;
L = [a, a, a] ;
L = [a, a, b] ;
L = [a, a, c] ;
L = [a, b, a]
这是迭代深化的常用习惯用法,它允许您公平地列出所有答案。在这种情况下,我不认为clpfd会帮助你。
修改强>
我在标题中看到你明确询问CLPFD。你的代码不起作用的原因是当你做
时L in 0..Bound
您实际上并未枚举这些值。对于下一个谓词,L仍然是未绑定的并且带有约束。所以membersWithLength将继续循环尝试新的长度,并且一旦实例化它的长度,它将看到约束失败并再次尝试。您可以在以下示例中看到它:
L in 0..2, length(X, L)
在代码中循环,因为长度不断尝试。如果要限制它,必须在调用length之前实例化L.您可以使用标签。下一个示例不会循环:
L in 0..2, label([L]), length(X, L)