计算一个条款的调用次数

时间:2012-07-06 14:55:35

标签: recursion count prolog clause

我有一个如下的条款:

lock_open:-
        conditional_combination(X),
        equal(X,[8,6,5,3,6,9]),!,
        print(X).

这个条款成功了。但是我想知道在equal(X,[8,6,5,3,6,9])变为真之前调用了多少次conditional_combination()。该程序是通过遵循一些规则来生成排列。我需要生成多少个排列来获得像865369这样的特定值。

3 个答案:

答案 0 :(得分:12)

你真正想要的是略有不同:你想要计算一个目标的答案数量(到目前为止)。

以下谓词call_nth(Goal_0, Nth)成功,如call(Goal_0),但有一个额外的参数,表明找到的答案是第n个答案。该定义非常特定于SWI或YAP。 在您的常规程序中使用nb_setarg/3之类的内容,但将它们用于包装良好的案例中。甚至在内 在这两个系统中,这些结构的确切含义对于一般情况没有明确定义。 Here is a definition for SICStus

call_nth(Goal_0, C) :-
   State = count(0,_), % note the extra argument which remains a variable
   Goal_0,
   arg(1, State, C1),
   C2 is C1+1,
   nb_setarg(1, State, C2),
   C = C2.

Eclipse提供了更强大的抽象:

call_nth(Goal_0, Nth) :-
   shelf_create(counter(0), CounterRef),
   call(Goal_0),
   shelf_inc(CounterRef, 1),
   shelf_get(CounterRef, 1, Nth).
?- call_nth(between(1,5,I),Nth).
I = Nth, Nth = 1 ;
I = Nth, Nth = 2 ;
I = Nth, Nth = 3 ;
I = Nth, Nth = 4 ;
I = Nth, Nth = 5.

所以简单地把它包起来:

lock_open :-
   call_nth(conditional_combination(X), Nth),
   X = [8,6,5,3,6,9],
   !,
   ....

答案 1 :(得分:5)

如果您使用SWI prolog,可以使用nb_getval/2nb_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来保存当前的目标计数器。您可以使用任何未在您的程序中使用的术语。

答案 2 :(得分:1)

在研究“微型”模块时,我最近发明了枢轴。它们受到线程/管道模式的启发而传递数据。枢轴是最大长度为1的有界队列,pivot_put / 1也会复制给定项。但是出于性能原因,它们不使用同步且非阻塞。

到目前为止,它们与nb_setarg / 3非常相似,除了它们不破坏Prolog术语,而是更新Java数据结构。结果,它们比非逻辑术语操作更安全。同样,它们不需要一些call_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.

有了数据透视,甚至没有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.