Recursion 计算子句的调用数

Recursion 计算子句的调用数,recursion,count,prolog,clause,Recursion,Count,Prolog,Clause,我有一个条款如下: lock_open:- conditional_combination(X), equal(X,[8,6,5,3,6,9]),!, print(X). 锁定打开:- 条件_组合(X), 等于(X,[8,6,5,3,6,9]),!, 打印(X)。 本条款生效。但是我想知道在equal(X,[8,6,5,3,6,9])变为真之前,条件_composition()被调用了多少次。该程序通过遵循一些规则来生成置换。我需要知道需要生成多少

我有一个条款如下:

lock_open:- conditional_combination(X), equal(X,[8,6,5,3,6,9]),!, print(X). 锁定打开:- 条件_组合(X), 等于(X,[8,6,5,3,6,9]),!, 打印(X)。
本条款生效。但是我想知道在
equal(X,[8,6,5,3,6,9])
变为真之前,条件_composition()被调用了多少次。该程序通过遵循一些规则来生成置换。我需要知道需要生成多少个置换才能得到865369这样的特定值。

如果您使用SWI prolog,您可以使用
nb_getval/2
nb_setval/2
来实现您想要的:

lock_open:- 
  nb_setval(ctr, 0),  % Initialize counter
  conditional_combination(X), 
  nb_inc(ctr),  % Increment Counter
  equal(X,[8,6,5,3,6,9]),
  % Here you can access counter value with nb_getval(ctr, Value)
  !, 
  print(X).

nb_inc(Key):-
  nb_getval(Key, Old),
  succ(Old, New),
  nb_setval(Key, New).

其他prolog也有其他方法来做同样的事情,在prolog实现中寻找全局变量。在这段代码中,我使用术语
ctr
来保存当前目标计数器。您可以使用程序中未使用的任何术语。

您真正想要的是稍微不同的东西:您想要计算一个目标的答案数(到目前为止)

下面的谓词
call\n(Goal\u 0,nth)
call(Goal\u 0)
一样成功,但有一个附加参数指示找到的答案是第n个答案。该定义对SWI或YAP具有高度特异性。不要在您的常规程序中使用类似于
nb_setarg/3
的东西,但要将它们用于封装良好的情况,如本例。甚至在 在这两个系统中,这些结构的确切含义在一般情况下没有得到很好的定义

?呼叫n(介于(1,5,I)和n之间)。 I=n,n=1; I=n,n=2; I=n,n=3; I=n,n=4; I=n,n=5。 因此,简单地把它包装起来:

lock_open :- call_nth(conditional_combination(X), Nth), X = [8,6,5,3,6,9], !, .... 锁定打开:- 调用n次(条件组合(X),n次), X=[8,6,5,3,6,9], !, .... 在制作“micro”模块时,我最近发明了枢轴。它们的灵感来自于传递数据的螺纹/管道模式。pivot是一个最大长度为1的有界队列,pivot_put/1也会复制给定项。但出于性能方面的原因,它们不使用同步和非阻塞

就目前而言,它们与nb_setarg/3非常相似,只是它们不破坏Prolog术语,而是更新Java数据结构。因此,它们比非逻辑项操作稍微安全一点。而且它们不需要一些调用_cleanup/3,因为它们是Java垃圾收集的

就目前而言,它们比nb_setarg/3更相似,而不是使用一些显式的分配和解除分配结构。例如,SICStus Prolog的解决方案可以是:

call_nth(Goal_0, Nth) :-
   new(unsigned_32, Counter),
   call_cleanup(call_nth1(Goal_0, Counter, Nth),
           dispose(Counter)).

call_nth1(Goal_0, Counter, Nth) :-
   call(Goal_0),
   get_contents(Counter, contents, Count0),
   Count1 is Count0+1,
   put_contents(Counter, contents, Count1),
   Nth = Count1.
使用pivots,甚至没有32位限制,我们可以直接执行以下操作:

call_nth(G, C) :-
   pivot_new(P),
   pivot_put(P, 0),
   call(G),
   pivot_take(P, M),
   N is M+1,
   pivot_put(P, N),
   C = N.

条件组合/1
中调用
nb_setval/2
会影响结果。像
ctr
这样的名称可能用于其他计数…@false:true,OP应该使用程序中未使用的任何术语。问题是,如果不检查整个程序,您无法保证这一点。您是对的,但如果您采取这种立场,那么您将永远不会使用assert/call/retract或任何具有全局效果的术语。事实上,就像在任何语言中一样,如果你使用任何全球语言,你都必须谨慎……我不同意:更新知识库需要像assert/retract这样的东西。还有一些方法可以防止一个全球卫星的多种用途成为可能。以使用asserta/retract的findall/3为例。您不能嵌套这样的调用,也不能同时有两个调用。我看到了一种使用这样的原语在时间和空间上实现聚合器O(N)的方法。谢谢必须重新考虑limit/2和offset/2的实现,可能更原始、更通用的谓词是call\n/2。我没有意识到可以这样调用目标(清单
call\n/2
的第三行)。我以为一个人总是需要呼叫(目标),但显然,只要
目标就足够了!
lock_open :-
   call_nth(conditional_combination(X), Nth),
   X = [8,6,5,3,6,9],
   !,
   ....
call_nth(Goal_0, Nth) :-
   new(unsigned_32, Counter),
   call_cleanup(call_nth1(Goal_0, Counter, Nth),
           dispose(Counter)).

call_nth1(Goal_0, Counter, Nth) :-
   call(Goal_0),
   get_contents(Counter, contents, Count0),
   Count1 is Count0+1,
   put_contents(Counter, contents, Count1),
   Nth = Count1.
call_nth(G, C) :-
   pivot_new(P),
   pivot_put(P, 0),
   call(G),
   pivot_take(P, M),
   N is M+1,
   pivot_put(P, N),
   C = N.