我想在prolog中创建一个计数器。
启动init / 0之类的东西。 添加1个增量/ 0, 和get_counter / 1之类的东西。获得价值。
但是我不知道如果你有没有输入的init / 0如何将东西设置为0,那么如何启动它。
有人可以给我一些提示,我应该怎么做呢?
我不是母语人士,所以如果不清楚我的意思我很抱歉。
答案 0 :(得分:1)
解决此问题的一种声明方式是将此视为两个计数器值之间的关系:一个在增量之前,一个在增量之后。
您可以使用CLP(FD)约束来关联两个计数器值:
counter_next(C0, C) :- C0 + 1 #= C.
这样的谓词是完全纯粹的,可以在所有方向上使用。
这种关系的序列描述了重复递增计数器,将初始值与其最终状态相关联:
?- S0 = 0, counter_next(S0, S1), counter_next(S1, S). S = 2, S0 = 0, S1 = 1
编辑:假设您采用其他方式并设法实现0-ary谓词increment/0
,正如您所要求的那样,破坏性地增加全局资源。然后你会有严重的声明性问题。例如,递增计数器必须成功,因此我们可以看到:
?- increment.
true.
但这意味着原始查询不再等同于自己的答案,因为查询:
?- true.
true.
肯定不会增加柜台。
这也意味着您无法再孤立地测试和推理您的谓词,但必须始终考虑全局资源。
这反过来会使您更难理解和纠正代码中的错误。
因此,我强烈建议您采用声明性方式来考虑此任务,并在增量显式之前和之后建立计数器值之间的关系。作为额外的好处,您还可以在另一个方向上使用这些关系,并询问:“当递增时,哪个初始计数器值(如果有的话)会产生给定值?”,或者更一般地说:“对于哪些参数,这种关系甚至持有?“
答案 1 :(得分:1)
这是你想要实现的目标:
?- X0 = 0 /* init */, succ(X0, X1) /* inc */, succ(X1, X2) /* inc */.
X0 = 0,
X1 = 1,
X2 = 2.
init
只是给变量一个值,递增是用succ/2
完成的,getval
是隐含的。
但是,正如我在评论中已经说过的,考虑你的用例!如果您想要跟踪循环内部的深度,可以使用succ/2
或甚至跟suggestion by @mat进行操作。
因此,要计算列表中foo
的数量:
list_foos([], 0).
list_foos([X|Xs], N) :-
( dif(X, foo)
-> list_foos(Xs, N)
; list_foos(Xs, N0),
succ(N0, N) % or: N0 + 1 #= N
).
您应该同时试用succ(N0, N)
和N0 + 1 #= N
,看看如果list_foos/2
的一个或两个参数都不存在,您将如何使用它们。
但是,如果由于某种原因需要维护全局状态:例如,您正在动态更改数据库,并且需要为表生成增加的整数键。然后,您应该考虑answer by @coredump。请记住,一旦开始使用“全局”变量,编写在任何Prolog实现上运行的代码并不是一件容易的事。一种尝试是使用predicates for manipulating the database:
:- dynamic foocounter/1.
initfoo :-
retractall(foocounter(_)),
assertz(foocounter(0)).
incrfoo :-
foocounter(V0),
retractall(foocounter(_)),
succ(V0, V),
assertz(foocounter(V)).
然后,您现在可以使用全局状态(它不需要像您的示例一样使用):
?- initfoo.
true.
?- incrfoo.
true.
?- incrfoo.
true.
?- foocounter(V).
V = 2.
这是完全有效的代码,但存在许多缺陷,因此请谨慎使用。
答案 2 :(得分:0)
我会使用ECLiPSe's non-local variables:
init :- setval(counter, 0).
increment :- incval(counter).
get_counter(V) :- getval(counter, V).
您的实施可能提供类似的东西。在SWI-prolog中,似乎可以使用nb_setval
(非可回溯的setval)实现相同的目的。