Prolog如何在不使用内置函数的情况下计算事实的数量

Prolog如何在不使用内置函数的情况下计算事实的数量,prolog,Prolog,考虑到许多事实,有没有一种方法可以不使用内置函数来计算它们呢?我已经用下面的代码尝试过这样做,但没有成功。我希望有人能帮助我。 例如,以下事实: stops(jubilee,bondstreet,1). stops(jubilee,waterloo,2). stops(jubilee,bakerstreet,3). 到目前为止,守则的内容是: findStops(X) :- stops(X,_, N), N1 is N+1, stopsX,_,N1). 我想这样做,N1是jubilee线如何

考虑到许多事实,有没有一种方法可以不使用内置函数来计算它们呢?我已经用下面的代码尝试过这样做,但没有成功。我希望有人能帮助我。 例如,以下事实:

stops(jubilee,bondstreet,1).
stops(jubilee,waterloo,2).
stops(jubilee,bakerstreet,3).
到目前为止,守则的内容是:

findStops(X) :- stops(X,_, N), N1 is N+1, stopsX,_,N1).

我想这样做,N1是jubilee线如何停止的计数器。

一个简单的解决方案是计算第一个参数中包含原子
jubilee
停止/3
事实的数量。假设
stops/3
谓词的所有子句都有一个绑定的第一个参数,您可以编写:

?- findall(1, stops(jubilee,_,_), List), length(List, Count).
在这个查询中,
findall/3
是标准的Prolog谓词,
length/2
是事实上的标准谓词,通常作为内置谓词或库谓词提供


您能否将此查询转换为一个谓词,该谓词将站作为参数(而不是硬编码的站作为
jubilee
),并返回该站的计数?

这个问题并不完全清楚,因为还没有定义“内置”谓词所允许的内容。如果不使用某种预定义的谓词,就无法解决这样的问题

这里还有一些其他的想法

使用
assertz
retract

count_stops(Count) :-
    assertz(num_stops(0)),
    count_stops_aux(Count).

count_stops_aux(_) :-
    stops(_, _, _),
    retract(num_stops(C)),
    C1 is C + 1,
    assertz(num_stops(C1)),
    fail.
count_stops_aux(Count) :-
    retract(num_stops(Count)).
您也可以使用SWI Prolog的
b_setval/2
b_getval/2
执行类似的操作

下面是一个递归解决方案,它使用一个列表来检查我们是否已经统计了一个特定的事实:

count_stops(Count) :-
    count_stops_aux([], 0, Count).

count_stops_aux(L, Count, Total) :-
    stops(A, B, C),
    \+ member(stops(A,B,C), L),
    C is Count + 1,
    count_stops_aux([stops(A,B,C)|L], C, Total), !.
count_stops_aux(_, Total, Total).
或者类似地,但也使用
length/2

count_stops(Count) :-
    count_stops_aux([], Facts),
    length(Facts, Count).

count_stops_aux(L, Facts) :-
    stops(A, B, C),
    \+ member(stops(A,B,C), L),
    count_stops_aux([stops(A,B,C)|L], Facts), !.
count_stops_aux(Facts, Facts).

第一种解决方案将计算冗余事实(如果相同事实存在不止一次),并且
assertz
retract
是缓慢的操作。第二个和第三个解决方案不会计算多余的事实,但实际上只是保罗解决方案的笨拙、冗长版本,以避免使用
findall
。这就是为什么Prolog有诸如
findall/3
bagof/3

之类的谓词提示:列出您检索的结果,以防止两次收到相同的事实。@WillemVanOnsem有方法递归添加结果吗?您编写
N1 is N+1
,因此您使用的是内置的
(is)/2