我目前在Prolog中有这段代码
s1(Q,100) :- generate(Q).
generate([X,Y,S,P]) :-
nat(X, 49),
nat(Y, 98),
S is X+Y,
P is X*Y,
S =< 100,
X < Y.
nat(2,_).
nat(X,N) :-
N > 2,
M is N - 1,
nat(Y,M),
X is Y + 1.
它目前会生成一个四元组列表X, Y, S, P
,以便
这有效并创建所有可能的解决方案,但有多个答案(即每次都必须按;
才能获得下一个结果。)
如何从所有这些结果中形成单个列表,例如
[[2, 3, 5, 6], [2, 4, 6, 8], ...]
没有使用任何内置谓词,例如findall/3
?
答案 0 :(得分:2)
首先,您为X
和Y
提供的上限间隔都是一个:
1 < X < 49
与nat(X,49)
不匹配,1 < X =< 49
无效。1 < Y < 98
与nat(Y,98)
不匹配,1 < Y =< 98
无效。让我们开始吧!
如果您想使用findall/3
(等)收集而不的所有解决方案,一种方法是计算两个列表的Cartesian product(又名交叉产品){{ 1}}和Xs
。
要获得Ys
和Xs
,我们可以使用内置谓词numlist/3
:
Ys
要将?- numlist(2,49,Xs).
Xs = [2,3,4,/* consecutive integers from 5 to 47 omitted */,48,49].
?- numlist(2,98,Ys).
Ys = [2,3,4,/* consecutive integers from 5 to 96 omitted */,97,98].
中的每个X
与Xs
中的每个Y
合并,我们会使用dcg xproduct//3
。
要选择要收集的四元组,请使用语法规则Ys
:
x_y_maybe_quadruple//2
让我们把它们放在一起!
x_y_maybe_quadruple(X,Y) -->
( { 1 < X, X < Y, X+Y =< 100 } % if all these conditions are met
-> { P is X * Y },
{ S is X + Y },
[[X,Y,S,P]] % then add single "quadruple"
; [] % else add nothing.
).
那么......如果我们使用?- numlist(2,49,Xs),
numlist(2,98,Ys),
phrase(xproduct(x_y_maybe_quadruple,Xs,Ys),Qss).
Qss = [[2,3,5,6],[2,4,6,8],
/* lots of other quadruples omitted */,
[48,51,99,2448],[48,52,100,2496]].
,我们实际上会得到所有四倍吗?
findall/3
它有效!不仅如此:我们在完全相同的订单中获得完全相同的四倍!
答案 1 :(得分:0)
如果列表中尚未包含解决方案,则需要在列表中添加解决方案...如果列表中的解决方案失败。
所以
myfindall(List) :-
my_find(List,[]),
!.
my_find(List,Ac) :-
s1(Q,100),
my_set(Q,Ac,NewAc),
my_find(List,NewAc).
my_find(Ac,Ac).
my_set(X,[],[X]) :-
!.
my_set(H,[H|_],_) :-
!,
fail.
my_set(X,[H|T],L) :-
my_set(X,T,Rtn),
L = [H|Rtn].