我想做的是从给定列表中生成元素的所有组合。例如:从 [a,b,c],我可能想要:
[]
[a]
[b]
[c]
[a,a]
[a,b]
[a,c]
[b,a]
...
等等。也许有一个神奇的序言单线可以做到这一点。如果是这样,我很想听听。
但是,我的问题与其说是解决这个特定问题,不如说是请求有人为我解释 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