这个问题在回答another question on StackOverflow时(概括了一下)产生了所有由有限元素组构成的序列而没有重复出现。
正如鲍里斯在评论中正确指出的那样,这个问题有许多现有的解决方案。但是,我感兴趣的是一个不使用累加器的解决方案(即,已经挑选过的元素列表,要与之比较一个新选择的元素),而是使用dif/2
语句。
为了说明,在我的下面的程序中,我有4个元素,并且在4个递归调用之后,有两个div/2
语句,这些语句指出到目前为止已经选择的4个元素是成对不相似的。从这一点可以推断,继续递归并寻找第五个元素是没有意义的,因为给定div/2
语句没有剩余的元素。有没有办法将这种“知识”编码到程序中,以便它不再循环?
:- use_module(library(apply)).
:- use_module(library(dif)).
sequences([]).
sequences([H|T]):-
maplist(dif(H), T),
between(1, 4, H),
sequences(T).
当前的循环行为:
?- sequences(X).
X = [] ;
X = [1] ;
...
X = [4, 3, 1, 2] ;
X = [4, 3, 2, 1] ;
<LOOP>
答案 0 :(得分:2)
不是真正的答案,但评论的时间太长了:
您的问题是您希望将元素保留为事实。将它们放在列表中,您可以使用select/3
从该列表中取出一个元素。只要你把它们作为事实,这将比它需要的更圆(我觉得)。排序列表(基数通常有订单)是在Prolog中表示集合的完美好方法。
编辑:
由于我仍然不确定我是否理解你的问题,所以这是我认为你问的问题的实际答案:
请勿使用dif/2
,因为没有必要。相反,例如:
combination([], _).
combination([X|Xs], Set) :-
select(X, Set, Set0),
combination(Xs, Set0).
在这里,您必须使用setof/3
或另一个构建所有解决方案列表的谓词来构建初始集。如果您可以使用列表并dif/2
,则无法看到select/3
的必要性。
但如果你真的坚持,我会这样做:
set_el(a).
set_el(b).
set_el(c).
set_el_combination(Combination) :-
set_el_combination_1([], Combination).
set_el_combination_1(C, R) :-
reverse(C, R).
set_el_combination_1(C0, C) :-
maplist(dif(X), C0),
set_el(X),
set_el_combination_1([X|C0], C).
您会注意到解决方案的顺序是不同的(正确的词典顺序),这是预期的。如果要避免在最后反转,可以使用差异列表。我相信这也可以写成DCG。
这有帮助吗?
答案 1 :(得分:2)
开始时的小问题 - 名称:sequences/1
表示序列列表(无论序列是什么),它应该是sequence/1
。
你要求很多糟糕的Prolog系统:你要求更强的一致性。无论如何,我猜想。
我的即时反应(使用library(clpfd)
!)不起作用,让我们看看为什么
?- length(Xs,N),Xs ins 1..4, all_distinct(Xs).
它的循环次数与您的版本一样多,使用此failure-slice:
可以最好地看到它?- length(Xs,N), false,Xs ins 1..4, all_distinct(Xs).
因此length/2
已经错了。也许我重申你的程序,并尝试找出你的程序没有终止的原因:
sequences([]) :- false. sequences([H|T]):- maplist(dif(H), T), falsebetween(1, 4, H),sequences(T). ?- sequences(X), false.
我们最亲切的声明性海报儿童maplist/2
在flagranti中抓住了 !好吧,也许我们不应该那么苛刻。毕竟,诚实的不终止谓词总是比不合理的不完整或不完整的黑客更好。
我们需要了解的是all_distinct/1
要求知道列表的长度,并且所有域名也必须存在。
sequence(Xs) :-
sequence_aux(Xs, []).
sequence_aux([], _).
sequence_aux([X|Xs], Ys) :-
X in 1..4,
all_distinct([X|Ys]),
sequence_aux(Xs, [X|Ys]).
?- sequence(X).
现在终止。
@mat可能会注意到all_distinct([_])
可能会被删除。甚至可能更多。
如果您不喜欢此解决方案,因为它使用了额外的参数,则需要实现更安全的maplist/2
。
fmaplist(C_1, Xs) :-
freeze(Xs, fmaplist_aux(C_1, Xs)).
fmaplist_aux(_C_1, []).
fmaplist_aux(C_1, [X|Xs]) :-
call(C_1, X),
freeze(Xs, fmaplist_aux(C_1, Xs)).
现在您可以逐字使用原始程序。但我觉得它并不擅长。了解冻结程序中非终止的精确边界要困难得多。
顺便说一句:您可能会尝试在SWI中获取正确的变量名称以进行答案替换,因为_G772
- 类似的编号不允许将答案重新粘贴回顶层shell并获得正确的结果。< / p>