Prolog计算谓词为真的次数

Vic*_*aga 23 prolog

我想计算自定义谓词为真的次数.例如,我有以下代码:

is_man(john).
is_man(alex).
?:-is_man(X).
Run Code Online (Sandbox Code Playgroud)

X将返回john,然后如果我按分号,它也将返回alex,然后返回false.

我想建立像:

count(is_man(X), Count).
Run Code Online (Sandbox Code Playgroud)

而这回归

Count = 2
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

Kaa*_*rel 28

在SWI-Prolog中:

aggregate_all(count, is_man(X), Count).
Run Code Online (Sandbox Code Playgroud)

  • @Shevliaskovic:简短的回答是肯定的,这是可能的.`aggregate_all/3`上面使用`findall/3`并计算回溯找到的解决方案,包括相同的解决方案.但是`aggregate_all/4`和`aggregate/4`允许[以无视重复的方式]进行计数(http://www.swi-prolog.org/pldoc/man?section=aggregate).您可能需要另外提出一个问题. (2认同)

har*_*ath 11

对于ISO标准Prolog解决方案,您可以使用findall/3生成所有解决方案的列表,然后将Count设置为结果列表的长度.如你所提议的那样将它包装成用户定义的谓词count/2可能有点棘手,因为我们需要以一种方式形成findall/3的第一个参数,以便解释目标中的任何空闲(未绑定)变量想要传递count/2的第一个参数.

许多Prolog提供"计数器"或其他形式的可变全局值,非标准扩展,可以与故障驱动的"循环"结合使用以进行相同的计数.略微繁琐但坚持Prolog标准的字母将是使用断言和收回来通过调整动态事实来创建自己的"计数器".

以下是后一种方法的说明.使其"多线程安全"需要额外的逻辑.

count(Goal,_) :-
    setGoalCount(0),
    call(Goal),
    incGoalCount(1),
    fail.              /* or false in some Prologs */
count(_,Count) :-
    getGoalCount(Count).

setGoalCount(_) :-
    retract(getGoalCount(_)),
    fail.
setGoalCount(X) :-
    assert(getGoalCount(X)).

incGoalCount(Y) :-
    retract(getGoalCount(X)),
    !,
    Z is X + Y,
    assert(getGoalCount(Z)).
Run Code Online (Sandbox Code Playgroud)

  • 这不是"多线程安全".简单的嵌套不起作用`count(count((true; true),_),C).`应该给1,但你得到3.另外,ISO没有`assert/1`但是`asserta/1`和`assertz/1`. (3认同)
  • 嗨,是的,让我想起我们最近有的comp.lang.prolog帖子!如果不需要findall/3或"全局变量"解决方案,那么它也是sys_make_surrogate/1和setup_call_cleanup/3的商业案例. (2认同)

小智 5


count(P,Count) :-
        findall(1,P,L),
        length(L,Count).
Run Code Online (Sandbox Code Playgroud)