目前尚不清楚“满意10倍”是什么意思。你的意思是r1/2
谓词将有10个解决方案吗?一个例子是目标member(X, [1,2,3,4,5,6,7,8,9,0])
,其在回溯时将连续实例化变量X
到每个列表元素。如果是这样,一种解决方案可能是使用标准的findall/3
谓词来计算目标的所有解决方案的列表,然后计算列表的长度。例如:
r1_10(X,Z) :-
findall(_, r1(X,Z), Solutions),
length(Solutions, 10).
该断言可以通过使用附加的参数来传递的解决方案,以检查的数量很容易地推广。它也可以通过使用另一个参数来通过目标本身来推广。另一方面,如果你想简单地调用一个目标N次,你可以定义一个需要一个目标和一个计数器的谓词。例如:
call_n_times(N, Goal) :-
between(1, N, _), % generate, on backtracking, all numbers in the interval [1,N]
once(Goal),
fail.
call_n_times(_, _).
但是,此定义假定目标永远不会失败(或引发错误)。从你的问题来看,如果目标不能满足N次,应该会发生什么。在这种情况下,呼叫者是否应该失败?如果是这样,你将需要一个不同的定义。例如(再次假设目标从未失败或引发错误):
call_n_times(0, _) :- !. % green cut just to avoid a spurious choice-point
call_n_times(N, Goal) :-
N > 0,
once(Goal),
M is N - 1,
call_n_times(M, Goal).
但是这个定义仍然可能会有问题。例如,如果你传递一个非地面目标,即有变量的目标,并且调用该目标,则会以阻止其在下一步中成功的方式实例化其所有变量的一部分。为了避免这种潜在的问题的一种方法是使用下面的紧凑型定义:
call_n_times(N, Goal) :-
forall(between(1,N,_), Goal).
forall/2
和between/3
是事实上的标准谓词。对于第一个参数的每个解决方案,第二个参数为true(因此实现生成和测试循环)时,forall/2
谓词为true。
我们可以使用一些更多细节,包括你想要完成什么,包括你想要重复的目标的性质。